Skip to content

Commit

Permalink
Emit PT_GNU_PROPERTY program header if .note.gnu.property is present
Browse files Browse the repository at this point in the history
It looks like Linux kernel reads this program header to enable BTI on ARM64.
  • Loading branch information
rui314 committed Aug 15, 2024
1 parent c295648 commit 23bc92c
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 23 deletions.
8 changes: 6 additions & 2 deletions src/arch-arm32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,11 @@ u64 get_eflags(Context<E> &ctx) {
void fixup_arm_exidx_section(Context<E> &ctx) {
Timer t(ctx, "fixup_arm_exidx_section");

OutputSection<E> *osec = find_section(ctx, SHT_ARM_EXIDX);
Chunk<E> *chunk = find_chunk(ctx, SHT_ARM_EXIDX);
if (!chunk)
return;

OutputSection<E> *osec = chunk->to_osec();
if (!osec)
return;

Expand Down Expand Up @@ -780,7 +784,7 @@ void fixup_arm_exidx_section(Context<E> &ctx) {
// .ARM.exidx's sh_link should be set to the .text section index.
// Runtime doesn't care about it, but the binutils's strip command does.
if (ctx.shdr) {
if (Chunk<E> *text = find_section(ctx, ".text")) {
if (Chunk<E> *text = find_chunk(ctx, ".text")) {
osec->shdr.sh_link = text->shndx;
ctx.shdr->copy_buf(ctx);
}
Expand Down
1 change: 1 addition & 0 deletions src/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ enum : u32 {
PT_GNU_EH_FRAME = 0x6474e550,
PT_GNU_STACK = 0x6474e551,
PT_GNU_RELRO = 0x6474e552,
PT_GNU_PROPERTY = 0x6474e553,
PT_OPENBSD_RANDOMIZE = 0x65a3dbe6,
PT_ARM_EXIDX = 0x70000001,
PT_RISCV_ATTRIBUTES = 0x70000003,
Expand Down
4 changes: 2 additions & 2 deletions src/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,10 +341,10 @@ template <typename E> u64 get_dtp_addr(const ElfPhdr<E> &);
//

template <typename E>
OutputSection<E> *find_section(Context<E> &ctx, u32 sh_type);
Chunk<E> *find_chunk(Context<E> &ctx, u32 sh_type);

template <typename E>
OutputSection<E> *find_section(Context<E> &ctx, std::string_view name);
Chunk<E> *find_chunk(Context<E> &ctx, std::string_view name);

template <typename E>
u64 get_eflags(Context<E> &ctx) {
Expand Down
32 changes: 17 additions & 15 deletions src/output-chunks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,18 @@ static u32 elf_hash(std::string_view name) {
}

template <typename E>
OutputSection<E> *find_section(Context<E> &ctx, u32 sh_type) {
Chunk<E> *find_chunk(Context<E> &ctx, u32 sh_type) {
for (Chunk<E> *chunk : ctx.chunks)
if (OutputSection<E> *osec = chunk->to_osec())
if (osec->shdr.sh_type == sh_type)
return osec;
if (chunk->shdr.sh_type == sh_type)
return chunk;
return nullptr;
}

template <typename E>
OutputSection<E> *find_section(Context<E> &ctx, std::string_view name) {
Chunk<E> *find_chunk(Context<E> &ctx, std::string_view name) {
for (Chunk<E> *chunk : ctx.chunks)
if (OutputSection<E> *osec = chunk->to_osec())
if (osec->name == name)
return osec;
if (chunk->name == name)
return chunk;
return nullptr;
}

Expand Down Expand Up @@ -267,6 +265,10 @@ static std::vector<ElfPhdr<E>> create_phdr(Context<E> &ctx) {
if (ctx.eh_frame_hdr)
define(PT_GNU_EH_FRAME, PF_R, ctx.eh_frame_hdr);

// Add PT_GNU_PROPERTY
if (Chunk<E> *chunk = find_chunk(ctx, ".note.gnu.property"))
define(PT_GNU_PROPERTY, PF_R, chunk);

// Add PT_GNU_STACK, which is a marker segment that doesn't really
// contain any segments. It controls executable bit of stack area.
{
Expand All @@ -293,8 +295,8 @@ static std::vector<ElfPhdr<E>> create_phdr(Context<E> &ctx) {

// Create a PT_ARM_EDXIDX
if constexpr (is_arm32<E>)
if (OutputSection<E> *osec = find_section(ctx, SHT_ARM_EXIDX))
define(PT_ARM_EXIDX, PF_R, osec);
if (Chunk<E> *chunk = find_chunk(ctx, SHT_ARM_EXIDX))
define(PT_ARM_EXIDX, PF_R, chunk);

// Create a PT_RISCV_ATTRIBUTES
if constexpr (is_riscv<E>)
Expand Down Expand Up @@ -734,19 +736,19 @@ static std::vector<Word<E>> create_dynamic_section(Context<E> &ctx) {
define(DT_STRSZ, ctx.dynstr->shdr.sh_size);
}

if (find_section(ctx, SHT_INIT_ARRAY)) {
if (find_chunk(ctx, SHT_INIT_ARRAY)) {
define(DT_INIT_ARRAY, ctx.__init_array_start->value);
define(DT_INIT_ARRAYSZ,
ctx.__init_array_end->value - ctx.__init_array_start->value);
}

if (find_section(ctx, SHT_PREINIT_ARRAY)) {
if (find_chunk(ctx, SHT_PREINIT_ARRAY)) {
define(DT_PREINIT_ARRAY, ctx.__preinit_array_start->value);
define(DT_PREINIT_ARRAYSZ,
ctx.__preinit_array_end->value - ctx.__preinit_array_start->value);
}

if (find_section(ctx, SHT_FINI_ARRAY)) {
if (find_chunk(ctx, SHT_FINI_ARRAY)) {
define(DT_FINI_ARRAY, ctx.__fini_array_start->value);
define(DT_FINI_ARRAYSZ,
ctx.__fini_array_end->value - ctx.__fini_array_start->value);
Expand Down Expand Up @@ -2949,8 +2951,8 @@ template class RelocSection<E>;
template class ComdatGroupSection<E>;
template class GnuDebuglinkSection<E>;

template OutputSection<E> *find_section(Context<E> &, u32);
template OutputSection<E> *find_section(Context<E> &, std::string_view);
template Chunk<E> *find_chunk(Context<E> &, u32);
template Chunk<E> *find_chunk(Context<E> &, std::string_view);
template i64 to_phdr_flags(Context<E> &ctx, Chunk<E> *chunk);
template ElfSym<E> to_output_esym(Context<E> &, Symbol<E> &, u32, U32<E> *);

Expand Down
11 changes: 7 additions & 4 deletions src/passes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1271,10 +1271,13 @@ void fixup_ctors_in_init_array(Context<E> &ctx) {
}
};

if (OutputSection<E> *osec = find_section(ctx, ".init_array"))
fixup(*osec);
if (OutputSection<E> *osec = find_section(ctx, ".fini_array"))
fixup(*osec);
if (Chunk<E> *chunk = find_chunk(ctx, ".init_array"))
if (OutputSection<E> *osec = chunk->to_osec())
fixup(*osec);

if (Chunk<E> *chunk = find_chunk(ctx, ".fini_array"))
if (OutputSection<E> *osec = chunk->to_osec())
fixup(*osec);
}

template <typename T>
Expand Down
10 changes: 10 additions & 0 deletions test/gnu-property.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
. $(dirname $0)/common.inc

cat <<EOF | $CC -o $t/a.o -c -xc -
int main() {}
EOF

$CC -B. -o $t/exe $t/a.o -no-pie
readelf -W --sections $t/exe | grep -Fqw .note.gnu.property || skip
readelf -W --segments $t/exe | grep -qw GNU_PROPERTY

0 comments on commit 23bc92c

Please sign in to comment.