Summary: | add --no-dynamic-linker option | ||
---|---|---|---|
Product: | binutils | Reporter: | Markus Trippelsdorf <markus> |
Component: | gold | Assignee: | Cary Coutant <ccoutant> |
Status: | NEW --- | ||
Severity: | normal | CC: | hjl.tools, i, ian |
Priority: | P2 | ||
Version: | 2.30 | ||
Target Milestone: | --- | ||
Host: | Target: | ||
Build: | Last reconfirmed: |
Description
Markus Trippelsdorf
2017-09-27 12:18:57 UTC
So perhaps: diff --git a/gold/layout.cc b/gold/layout.cc index 5f25faea5532..4fe4d6825223 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -2749,7 +2749,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, // if we saw a .interp section in an input file. if ((!parameters->options().shared() || parameters->options().dynamic_linker() != NULL) - && this->interp_segment_ == NULL) + && this->interp_segment_ == NULL + && !parameters->options().no_dynamic_linker()) this->create_interp(target); // Finish the .dynamic section to hold the dynamic data, and put diff --git a/gold/options.h b/gold/options.h index 93f81b29afcc..2b660c1e6d79 100644 --- a/gold/options.h +++ b/gold/options.h @@ -1050,6 +1050,9 @@ class General_options N_("Do not page align data, do not make text readonly"), N_("Page align data, make text readonly")); + DEFINE_bool(no_dynamic_linker, options::TWO_DASHES, '\0', false, + N_("Produce an executable with no program interpreter header"), NULL); + DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false, N_("Use less memory and more disk I/O " "(included only for compatibility with GNU ld)"), NULL); The following produces an static-pie executable that crashes on startup when it calls __pthread_initialize_minimal(): diff --git a/gold/gold.cc b/gold/gold.cc index a76d155f940a..a2dd31816acc 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -607,13 +607,6 @@ queue_middle_tasks(const General_options& options, (!input_objects->any_dynamic() && !parameters->options().output_is_position_independent()); set_parameters_doing_static_link(doing_static_link); - if (!doing_static_link && options.is_static()) - { - // We print out just the first .so we see; there may be others. - gold_assert(input_objects->dynobj_begin() != input_objects->dynobj_end()); - gold_error(_("cannot mix -static with dynamic object %s"), - (*input_objects->dynobj_begin())->name().c_str()); - } if (!doing_static_link && parameters->options().relocatable()) gold_fatal(_("cannot mix -r with dynamic object %s"), (*input_objects->dynobj_begin())->name().c_str()); diff --git a/gold/layout.cc b/gold/layout.cc index 5f25faea5532..5c531e470b66 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -2730,7 +2730,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, // Create the PT_PHDR segment which will hold the program // headers. - if (!this->script_options_->saw_phdrs_clause()) + if (!this->script_options_->saw_phdrs_clause() + && !parameters->options().no_dynamic_linker()) phdr_seg = this->make_output_segment(elfcpp::PT_PHDR, elfcpp::PF_R); // Create the dynamic symbol table, including the hash table. @@ -2749,7 +2750,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, // if we saw a .interp section in an input file. if ((!parameters->options().shared() || parameters->options().dynamic_linker() != NULL) - && this->interp_segment_ == NULL) + && this->interp_segment_ == NULL + && !parameters->options().no_dynamic_linker()) this->create_interp(target); // Finish the .dynamic section to hold the dynamic data, and put diff --git a/gold/options.cc b/gold/options.cc index ed63b6f04feb..15e77d6c2b67 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -1290,8 +1290,6 @@ General_options::finalize() gold_fatal(_("-shared and -static are incompatible")); if (this->shared() && this->pie()) gold_fatal(_("-shared and -pie are incompatible")); - if (this->pie() && this->is_static()) - gold_fatal(_("-pie and -static are incompatible")); if (this->shared() && this->relocatable()) gold_fatal(_("-shared and -r are incompatible")); diff --git a/gold/options.h b/gold/options.h index 93f81b29afcc..2b660c1e6d79 100644 --- a/gold/options.h +++ b/gold/options.h @@ -1050,6 +1050,9 @@ class General_options N_("Do not page align data, do not make text readonly"), N_("Page align data, make text readonly")); + DEFINE_bool(no_dynamic_linker, options::TWO_DASHES, '\0', false, + N_("Produce an executable with no program interpreter header"), NULL); + DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false, N_("Use less memory and more disk I/O " ================================================================================= ld.bfd: /* Initialize libpthread if linked in. */ if (__pthread_initialize_minimal != NULL) 91d6: 48 83 3d 32 90 09 00 cmpq $0x0,0x99032(%rip) # a2210 <__pthread_initialize_minimal> 91dd: 00 91de: 74 05 je 91e5 <__libc_start_main+0x245> __pthread_initialize_minimal (); 91e0: e8 9b f4 ff ff callq 8680 <__pthread_initialize_minimal@plt> Disassembly of section .plt: 0000000000008660 <__cxa_finalize@plt-0x10>: 8660: ff 35 ca 9c 09 00 pushq 0x99cca(%rip) # a2330 <_GLOBAL_OFFSET_TABLE_+0x8> 8666: ff 25 cc 9c 09 00 jmpq *0x99ccc(%rip) # a2338 <_GLOBAL_OFFSET_TABLE_+0x10> 866c: 90 nop 866d: 90 nop 866e: 90 nop 866f: 90 nop 0000000000008670 <__cxa_finalize@plt>: 8670: ff 25 ca 9c 09 00 jmpq *0x99cca(%rip) # a2340 <__cxa_finalize> 8676: 68 00 00 00 00 pushq $0x0 867b: e9 e0 ff ff ff jmpq 8660 <_init+0x20> 0000000000008680 <__pthread_initialize_minimal@plt>: 8680: ff 25 c2 9c 09 00 jmpq *0x99cc2(%rip) # a2348 <__pthread_initialize_minimal> 8686: 68 01 00 00 00 pushq $0x1 868b: e9 d0 ff ff ff jmpq 8660 <_init+0x20> ============================================================================== ld.gold: /* Initialize libpthread if linked in. */ if (__pthread_initialize_minimal != NULL) 8436: 48 83 3d 72 ae 29 00 cmpq $0x0,0x29ae72(%rip) # 2a32b0 <.got+0x98> 843d: 00 843e: 74 05 je 8445 <__libc_start_main+0x245> __pthread_initialize_minimal (); 8440: e8 c3 f5 ff ff callq 7a08 <.plt.got+0x48> Disassembly of section .plt: 0000000000007930 <.plt>: 7930: ff 35 ea b9 29 00 pushq 0x29b9ea(%rip) # 2a3320 <_GLOBAL_OFFSET_TABLE_+0x8> 7936: ff 25 ec b9 29 00 jmpq *0x29b9ec(%rip) # 2a3328 <_GLOBAL_OFFSET_TABLE_+0x10> 793c: 0f 1f 40 00 nopl 0x0(%rax) 7940: ff 25 ea b9 29 00 jmpq *0x29b9ea(%rip) # 2a3330 <_GLOBAL_OFFSET_TABLE_+0x18> 7946: 68 00 00 00 00 pushq $0x0 794b: e9 00 00 00 00 jmpq 7950 <.plt+0x20> 7950: ff 25 e2 b9 29 00 jmpq *0x29b9e2(%rip) # 2a3338 <_GLOBAL_OFFSET_TABLE_+0x20> 7956: 68 00 00 00 00 pushq $0x0 795b: e9 00 00 00 00 jmpq 7960 <.plt+0x30> 7960: ff 25 da b9 29 00 jmpq *0x29b9da(%rip) # 2a3340 <_GLOBAL_OFFSET_TABLE_+0x28> 7966: 68 00 00 00 00 pushq $0x0 796b: e9 00 00 00 00 jmpq 7970 <.plt+0x40> 7970: ff 25 d2 b9 29 00 jmpq *0x29b9d2(%rip) # 2a3348 <_GLOBAL_OFFSET_TABLE_+0x30> 7976: 68 00 00 00 00 pushq $0x0 797b: e9 00 00 00 00 jmpq 7980 <.plt+0x50> 7980: ff 25 ca b9 29 00 jmpq *0x29b9ca(%rip) # 2a3350 <_GLOBAL_OFFSET_TABLE_+0x38> 7986: 68 00 00 00 00 pushq $0x0 798b: e9 00 00 00 00 jmpq 7990 <.plt+0x60> 7990: ff 25 c2 b9 29 00 jmpq *0x29b9c2(%rip) # 2a3358 <_GLOBAL_OFFSET_TABLE_+0x40> 7996: 68 00 00 00 00 pushq $0x0 799b: e9 00 00 00 00 jmpq 79a0 <.plt+0x70> 79a0: ff 25 ba b9 29 00 jmpq *0x29b9ba(%rip) # 2a3360 <_GLOBAL_OFFSET_TABLE_+0x48> 79a6: 68 00 00 00 00 pushq $0x0 79ab: e9 00 00 00 00 jmpq 79b0 <.plt+0x80> 79b0: ff 25 b2 b9 29 00 jmpq *0x29b9b2(%rip) # 2a3368 <_GLOBAL_OFFSET_TABLE_+0x50> 79b6: 68 00 00 00 00 pushq $0x0 79bb: e9 00 00 00 00 jmpq 79c0 <.plt.got> Disassembly of section .plt.got: 00000000000079c0 <.plt.got>: 79c0: ff 25 5b b8 29 00 jmpq *0x29b85b(%rip) # 2a3221 <.got+0x9> 79c6: 66 90 xchg %ax,%ax 79c8: ff 25 5b b8 29 00 jmpq *0x29b85b(%rip) # 2a3229 <.got+0x11> 79ce: 66 90 xchg %ax,%ax 79d0: ff 25 63 b8 29 00 jmpq *0x29b863(%rip) # 2a3239 <.got+0x21> 79d6: 66 90 xchg %ax,%ax 79d8: ff 25 73 b8 29 00 jmpq *0x29b873(%rip) # 2a3251 <.got+0x39> 79de: 66 90 xchg %ax,%ax 79e0: ff 25 83 b8 29 00 jmpq *0x29b883(%rip) # 2a3269 <.got+0x51> 79e6: 66 90 xchg %ax,%ax 79e8: ff 25 9b b8 29 00 jmpq *0x29b89b(%rip) # 2a3289 <.got+0x71> 79ee: 66 90 xchg %ax,%ax 79f0: ff 25 9b b8 29 00 jmpq *0x29b89b(%rip) # 2a3291 <.got+0x79> 79f6: 66 90 xchg %ax,%ax 79f8: ff 25 a3 b8 29 00 jmpq *0x29b8a3(%rip) # 2a32a1 <.got+0x89> 79fe: 66 90 xchg %ax,%ax 7a00: ff 25 a3 b8 29 00 jmpq *0x29b8a3(%rip) # 2a32a9 <.got+0x91> 7a06: 66 90 xchg %ax,%ax 7a08: ff 25 a3 b8 29 00 jmpq *0x29b8a3(%rip) # 2a32b1 <.got+0x99> 7a0e: 66 90 xchg %ax,%ax 7a10: ff 25 db b8 29 00 jmpq *0x29b8db(%rip) # 2a32f1 <.got+0xd9> 7a16: 66 90 xchg %ax,%ax 7a18: ff 25 eb b8 29 00 jmpq *0x29b8eb(%rip) # 2a3309 <.got+0xf1> 7a1e: 66 90 xchg %ax,%ax I'm not sure I understand exactly what this option is for. If "-static -pie" will produce a static-pie executable, wouldn't such an executable already lack a dynamic linker? That's (part of) what -static does. What does the option have to do with the PT_PHDR header and segment? From the name & description, it sounds like it's intended to suppress the PT_INTERP header. If the option is also supposed to suppress the PT_PHDR header, shouldn't we issue a warning or an error if this option is used and we see a PHDRS clause in the linker script? (In reply to Cary Coutant from comment #3) > I'm not sure I understand exactly what this option is for. If "-static -pie" > will produce a static-pie executable, wouldn't such an executable already > lack a dynamic linker? That's (part of) what -static does. The problem is that when both "-static -pie" are used -pie currently forces PT_INTERP to be set. Generally "-static -pie" could be thought of as a hardened -static. % cat aslr.c #include <stdio.h> static void foo() {} static int bar = 5; int main() { int baz = 5; printf("function: %p, library function: %p, data: %p, stack: %p\n", foo, &printf, &bar, &baz); } (gcc trunk supports -static-pie, glibc with PIE libc.a is needed) ~ % gcc -fuse-ld=bfd -static-pie -fPIE aslr.c ~ % file a.out a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, for GNU/Linux 4.10.0, with debug_info, not stripped ~ % ldd ./a.out statically linked ~ % ./a.out function: 0x7f1c3fd130e5, library function: 0x7f1c3fd21b00, data: 0x7f1c3ffaf070, stack: 0x7ffeb1d24c0c ~ % ./a.out function: 0x7f137df070e5, library function: 0x7f137df15b00, data: 0x7f137e1a3070, stack: 0x7ffeeeb59eac > What does the option have to do with the PT_PHDR header and segment? From > the name & description, it sounds like it's intended to suppress the > PT_INTERP header. ld.bfd outputs no PT_PHDR header with -static-pie, so I just tried to copy its behavior. > If the option is also supposed to suppress the PT_PHDR header, shouldn't we > issue a warning or an error if this option is used and we see a PHDRS clause > in the linker script? Probably yes. But first we have to get the basic functionality working. (Also the labels for the output from comment 2 are wrong. They should be the other way round. ld.bfd output is ld.gold output and vice versa. Sorry.) Lack of --no-dynamic-linker makes gold unable to build glibc in --enable-static-pie mode mkdir -p out/gold cd out/gold ../../configure --prefix=/tmp/glibc/gold --enable-static-pie From ld.lld's experience, supporting the option is just a matter of: https://github.com/llvm/llvm-project/commit/0fbf28f7aae0ceb70071cac56de345e3ff04439c suppressing dynamic relocations for undefined weak symbols more aggressively. I have a summary about the linker behaviors in https://maskray.me/blog/2021-04-25-weak-symbol |