diff --git a/commandline.cc b/commandline.cc index 6f878c02..7af2e58d 100644 --- a/commandline.cc +++ b/commandline.cc @@ -277,6 +277,10 @@ void parse_nonpositional_args(std::span args, config.print_stats = true; } else if (read_z_flag(args, "now")) { config.z_now = true; + } else if (read_z_flag(args, "execstack")) { + config.z_execstack = true; + } else if (read_z_flag(args, "noexecstack")) { + config.z_execstack = false; } else if (read_flag(args, "fork")) { config.fork = true; } else if (read_flag(args, "no-fork")) { diff --git a/mold.h b/mold.h index 9b0ee7ba..7951112b 100644 --- a/mold.h +++ b/mold.h @@ -86,6 +86,7 @@ struct Config { bool shared = false; bool strip_all = false; bool trace = false; + bool z_execstack = false; bool z_now = false; i16 default_version = VER_NDX_GLOBAL; std::vector version_definitions; diff --git a/output_chunks.cc b/output_chunks.cc index 32cc89dd..7d92f954 100644 --- a/output_chunks.cc +++ b/output_chunks.cc @@ -151,11 +151,13 @@ std::vector create_phdr() { define(PT_GNU_EH_FRAME, PF_R, 1, out::eh_frame_hdr); // Add PT_GNU_STACK, which is a marker segment that doesn't really - // contain any segments. If exists, the runtime turn on the No Exeecute - // bit for stack pages. + // contain any segments. It controls executable bit of stack area. vec.push_back({}); vec.back().p_type = PT_GNU_STACK; - vec.back().p_flags = PF_R | PF_W; + if (config.z_execstack) + vec.back().p_flags = PF_R | PF_W | PF_X; + else + vec.back().p_flags = PF_R | PF_W; return vec; } diff --git a/test/execstack.sh b/test/execstack.sh new file mode 100755 index 00000000..7ae5c624 --- /dev/null +++ b/test/execstack.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -e +cd $(dirname $0) +echo -n "Testing $(basename -s .sh $0) ... " +t=$(pwd)/tmp/$(basename -s .sh $0) +mkdir -p $t + +cat < $t/log +grep -q 'GNU_STACK.* RWE ' $t/log + +clang -fuse-ld=`pwd`/../mold -o $t/exe $t/a.o -Wl,-z,execstack \ + -Wl,-z,noexecstack +readelf --segments -W $t/exe > $t/log +grep -q 'GNU_STACK.* RW ' $t/log + +clang -fuse-ld=`pwd`/../mold -o $t/exe $t/a.o +readelf --segments -W $t/exe > $t/log +grep -q 'GNU_STACK.* RW ' $t/log + +echo OK