From b1c0a13386cd2640c22a824565b526a03724995f Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 13 May 2022 19:36:27 +0800 Subject: [PATCH] [ELF] Add --rosegment and --no-rosegment Fixes https://github.com/rui314/mold/issues/514 --- elf/cmdline.cc | 6 ++++++ elf/mold.h | 1 + elf/output-chunks.cc | 8 +++++--- test/elf/rosegment.sh | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100755 test/elf/rosegment.sh diff --git a/elf/cmdline.cc b/elf/cmdline.cc index 37dd39c7..a37b8c91 100644 --- a/elf/cmdline.cc +++ b/elf/cmdline.cc @@ -113,6 +113,8 @@ Options: --require-defined SYMBOL Require SYMBOL be defined in the final output --retain-symbols-file FILE Keep only symbols listed in FILE --reverse-sections Reverses input sections in the output file + --rosegment Put read-only non-executable sections in their own segment (default) + --no-rosegment Put read-only non-executable sections in an executable segment --rpath DIR Add DIR to runtime search path --rpath-link DIR Ignored --run COMMAND ARG... Run COMMAND with mold as /usr/bin/ld @@ -537,6 +539,10 @@ std::vector parse_nonpositional_args(Context &ctx) { ctx.arg.shuffle_sections_seed = parse_number(ctx, "shuffle-sections", arg); } else if (read_flag("reverse-sections")) { ctx.arg.shuffle_sections = SHUFFLE_SECTIONS_REVERSE; + } else if (read_flag("rosegment")) { + ctx.arg.rosegment = true; + } else if (read_flag("no-rosegment")) { + ctx.arg.rosegment = false; } else if (read_arg("y") || read_arg("trace-symbol")) { ctx.arg.trace_symbol.push_back(arg); } else if (read_arg("filler")) { diff --git a/elf/mold.h b/elf/mold.h index def826bc..701e11dc 100644 --- a/elf/mold.h +++ b/elf/mold.h @@ -1593,6 +1593,7 @@ struct Context { bool relax = true; bool relocatable = false; bool repro = false; + bool rosegment = true; bool shared = false; bool stats = false; bool strip_all = false; diff --git a/elf/output-chunks.cc b/elf/output-chunks.cc index 77c90765..9bc5157d 100644 --- a/elf/output-chunks.cc +++ b/elf/output-chunks.cc @@ -116,10 +116,12 @@ static i64 to_phdr_flags(Context &ctx, Chunk *chunk) { return PF_R | PF_W | PF_X; i64 ret = PF_R; - if (chunk->shdr.sh_flags & SHF_WRITE) + bool write = (chunk->shdr.sh_flags & SHF_WRITE); + if (write) ret |= PF_W; - if ((chunk->shdr.sh_flags & SHF_EXECINSTR) || - (ctx.arg.z_separate_code == NOSEPARATE_CODE)) + if ((ctx.arg.z_separate_code == NOSEPARATE_CODE) || + (!ctx.arg.rosegment && !write) || + (chunk->shdr.sh_flags & SHF_EXECINSTR)) ret |= PF_X; return ret; } diff --git a/test/elf/rosegment.sh b/test/elf/rosegment.sh new file mode 100755 index 00000000..82761aaa --- /dev/null +++ b/test/elf/rosegment.sh @@ -0,0 +1,33 @@ +#!/bin/bash +export LC_ALL=C +set -e +CC="${TEST_CC:-cc}" +CXX="${TEST_CXX:-c++}" +GCC="${TEST_GCC:-gcc}" +GXX="${TEST_GXX:-g++}" +OBJDUMP="${OBJDUMP:-objdump}" +MACHINE="${MACHINE:-$(uname -m)}" +testname=$(basename "$0" .sh) +echo -n "Testing $testname ... " +cd "$(dirname "$0")"/../.. +t=out/test/elf/$testname +mkdir -p $t + +cat < +int main() { printf("Hello world\n"); } +EOF + +$CC -B. -o $t/exe1 $t/a.o +readelf -W --segments $t/exe1 > $t/log1 +! grep -q '\.interp .* \.text' $t/log1 || false + +$CC -B. -o $t/exe2 $t/a.o -Wl,--rosegment +readelf -W --segments $t/exe2 > $t/log2 +! grep -q '\.interp .* \.text' $t/log2 || false + +$CC -B. -o $t/exe3 $t/a.o -Wl,--no-rosegment +readelf -W --segments $t/exe3 > $t/log3 +grep -q '\.interp .* \.text' $t/log3 + +echo OK