Bug 22221 - add --no-dynamic-linker option
Summary: add --no-dynamic-linker option
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: gold (show other bugs)
Version: 2.30
: P2 normal
Target Milestone: ---
Assignee: Cary Coutant
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-09-27 12:18 UTC by Markus Trippelsdorf
Modified: 2021-07-28 22:49 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Trippelsdorf 2017-09-27 12:18:57 UTC
Now that static-pie is all the rage, it would be nice 
if the --no-dynamic-linker option could be added to gold.

 % ld.bfd --help | grep no-dynamic-linker
  --no-dynamic-linker   Produce an executable with no program interpreter header
Comment 1 Markus Trippelsdorf 2017-09-27 12:54:04 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);
Comment 2 Markus Trippelsdorf 2017-09-27 14:44:36 UTC
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
Comment 3 Cary Coutant 2017-09-28 00:46:19 UTC
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?
Comment 4 Markus Trippelsdorf 2017-09-28 08:36:55 UTC
(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.)
Comment 5 Fangrui Song 2021-07-28 22:49:21 UTC
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