gcc使用的实际默认链接描述文件和设置 [英] Actual default linker script and settings gcc uses

查看:117
本文介绍了gcc使用的实际默认链接描述文件和设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在哪里可以找到gcc使用的实际链接描述文件和设置?

Where can I find the actual linker script and settings gcc uses?

我尝试过的事情:

为具体起见,让我们考虑一个小程序: empty.c

For concreteness, let's consider a small program: empty.c

int main(void)
{   
    return 0;
}

以静态方式构建它,然后查看结果:

build it statically, and look at the result:

$ gcc -static -o empty empty.c
$ readelf -W -l empty

Elf file type is EXEC (Executable file)
Entry point 0x400f4e
There are 6 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x0bf581 0x0bf581 R E 0x200000
  LOAD           0x0bfeb0 0x00000000006bfeb0 0x00000000006bfeb0 0x001d80 0x0042d8 RW  0x200000
  NOTE           0x000190 0x0000000000400190 0x0000000000400190 0x000044 0x000044 R   0x4
  TLS            0x0bfeb0 0x00000000006bfeb0 0x00000000006bfeb0 0x000020 0x000058 R   0x10
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x0bfeb0 0x00000000006bfeb0 0x00000000006bfeb0 0x000150 0x000150 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .note.ABI-tag .note.gnu.build-id .rela.plt .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini .rodata __libc_subfreeres __libc_atexit __libc_thread_subfreeres .eh_frame .gcc_except_table 
   01     .tdata .init_array .fini_array .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs 
   02     .note.ABI-tag .note.gnu.build-id 
   03     .tdata .tbss 
   04     
   05     .tdata .init_array .fini_array .jcr .data.rel.ro .got 

请注意各个部分,将其分为多个部分,并放置在具有各种权限的内存区域中.

Note the various sections, grouped into segments, and placed into memory regions of various permissions.

现在让我们尝试获取有关如何进行此链接的尽可能多的信息.

Now let's attempt to get as much information as possible on how it did this linking.

$ gcc -static -o empty empty.c -Wl,--verbose
GNU ld (GNU Binutils for Ubuntu) 2.24
  Supported emulations:
   elf_x86_64
   elf32_x86_64
   elf_i386
   i386linux
   elf_l1om
   elf_k1om
   i386pep
   i386pe
using internal linker script:
==================================================
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
          "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
  .interp         : { *(.interp) }
  .note.gnu.build-id : { *(.note.gnu.build-id) }
  .hash           : { *(.hash) }
  .gnu.hash       : { *(.gnu.hash) }
  .dynsym         : { *(.dynsym) }
  .dynstr         : { *(.dynstr) }
  .gnu.version    : { *(.gnu.version) }
  .gnu.version_d  : { *(.gnu.version_d) }
  .gnu.version_r  : { *(.gnu.version_r) }
  .rela.dyn       :
    {
      *(.rela.init)
      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
      *(.rela.fini)
      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
      *(.rela.ctors)
      *(.rela.dtors)
      *(.rela.got)
      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
      *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
      *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
      *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
      *(.rela.ifunc)
    }
  .rela.plt       :
    {
      *(.rela.plt)
      PROVIDE_HIDDEN (__rela_iplt_start = .);
      *(.rela.iplt)
      PROVIDE_HIDDEN (__rela_iplt_end = .);
    }
  .init           :
  {
    KEEP (*(SORT_NONE(.init)))
  }
  .plt            : { *(.plt) *(.iplt) }
  .text           :
  {
    *(.text.unlikely .text.*_unlikely .text.unlikely.*)
    *(.text.exit .text.exit.*)
    *(.text.startup .text.startup.*)
    *(.text.hot .text.hot.*)
    *(.text .stub .text.* .gnu.linkonce.t.*)
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  }
  .fini           :
  {
    KEEP (*(SORT_NONE(.fini)))
  }
  PROVIDE (__etext = .);
  PROVIDE (_etext = .);
  PROVIDE (etext = .);
  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
  .rodata1        : { *(.rodata1) }
  .eh_frame_hdr : { *(.eh_frame_hdr) }
  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table
  .gcc_except_table.*) }
  /* These sections are generated by the Sun/Oracle C++ compiler.  */
  .exception_ranges   : ONLY_IF_RO { *(.exception_ranges
  .exception_ranges*) }
  /* Adjust the address for the data segment.  We want to adjust up to
     the same address within the page on the next page up.  */
  . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
  /* Exception handling  */
  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
  .exception_ranges   : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
  /* Thread Local Storage sections  */
  .tdata      : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
  .tbss       : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  }
  .init_array     :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
    PROVIDE_HIDDEN (__init_array_end = .);
  }
  .fini_array     :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
    PROVIDE_HIDDEN (__fini_array_end = .);
  }
  .ctors          :
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin.o(.ctors))
    KEEP (*crtbegin?.o(.ctors))
    /* We don't want to include the .ctor section from
       the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }
  .dtors          :
  {
    KEEP (*crtbegin.o(.dtors))
    KEEP (*crtbegin?.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
  }
  .jcr            : { KEEP (*(.jcr)) }
  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
  .dynamic        : { *(.dynamic) }
  .got            : { *(.got) *(.igot) }
  . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
  .got.plt        : { *(.got.plt)  *(.igot.plt) }
  .data           :
  {
    *(.data .data.* .gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  }
  .data1          : { *(.data1) }
  _edata = .; PROVIDE (edata = .);
  . = .;
  __bss_start = .;
  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.
      FIXME: Why do we need it? When there is no .bss section, we don't
      pad the .data section.  */
   . = ALIGN(. != 0 ? 64 / 8 : 1);
  }
  .lbss   :
  {
    *(.dynlbss)
    *(.lbss .lbss.* .gnu.linkonce.lb.*)
    *(LARGE_COMMON)
  }
  . = ALIGN(64 / 8);
  . = SEGMENT_START("ldata-segment", .);
  .lrodata   ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
  {
    *(.lrodata .lrodata.* .gnu.linkonce.lr.*)
  }
  .ldata   ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
  {
    *(.ldata .ldata.* .gnu.linkonce.l.*)
    . = ALIGN(. != 0 ? 64 / 8 : 1);
  }
  . = ALIGN(64 / 8);
  _end = .; PROVIDE (end = .);
  . = DATA_SEGMENT_END (.);
  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }
  .stabstr       0 : { *(.stabstr) }
  .stab.excl     0 : { *(.stab.excl) }
  .stab.exclstr  0 : { *(.stab.exclstr) }
  .stab.index    0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment       0 : { *(.comment) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
  /* DWARF 3 */
  .debug_pubtypes 0 : { *(.debug_pubtypes) }
  .debug_ranges   0 : { *(.debug_ranges) }
  /* DWARF Extension.  */
  .debug_macro    0 : { *(.debug_macro) }
  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}


==================================================
... <snip searching and linking actual object files>

但是该脚本虽然很长,但缺少前面列出的大多数导入信息.

But the script, while long, is missing most of the import information previously listed.

它如何知道将哪些部分收集到不同的载荷段中?
没有PHDRS命令,尽管SEGMENT_START的使用表明该系统在其他地方定义了一些标准段,但这些段中的 none 均未列出,并带有关联的段.

How does it know which sections to gather into different load segments?
There is no PHDRS command, and while the use of SEGMENT_START suggests there are some standard segments for this system defined somewhere else, none of the sections are listed with an associated segment.

此外,它如何知道将这些段加载到何处,或者这些内存区域具有什么权限?
没有MEMORY命令.同样,如果在其他地方为该系统定义了一些标准内存区域,则各节的 none 均列出要使用的内存区域.

Furthermore, how does it know where to load these segments, or what permissions these memory regions have?
There is no MEMORY command. And again, if there are some standard memory regions for this system defined somewhere else, none of the sections list which memory region to use.

当我看过以前用于微控制器的默认链接描述文件时,它们的详细程度令人难以置信.但是,此输出表明某个地方还有更多脚本和设置.

When I've seen default linker scripts before for microcontrollers, they were incredibly detailed. This output however suggests there are more scripts and settings somewhere.

这些其他链接描述文件定义和设置还存储在哪里?

Where are these other linker script definitions and settings stored?

推荐答案

好吧,我知道这是一个老问题,但是我也感到沮丧的是,在链接过程中没有关于所使用选项的准确信息.这个答案显示了我找到他们的旅程.

Well, I know that this is an old question, but I also found it frustrating that there is no precise info about options that are used during the linking process. This answer shows my journey to find them.

首先,我正在研究官方文档 https://gcc.gnu.org/onlinedocs/-我搜索了 GCC手册 GCC内部手册.我发现的唯一有意义的信息是gcc使用一个称为collect2的内部工具来调用链接器.根据 https://gcc.gnu.org/onlinedocs/gccint/Collect2.html 程序collect2通过链接一次程序并在链接器输出文件中查找具有特定名称的符号来表示它们是构造函数的方式来工作".因此,它用于使链接成为可能.

First of all, I was looking into official docs https://gcc.gnu.org/onlinedocs/ - I searched the GCC Manual and GCC Internals Manual. The only meaningful information that I found is that gcc uses an internal tool called collect2 to invoke the linker. According to https://gcc.gnu.org/onlinedocs/gccint/Collect2.html "The program collect2 works by linking the program once and looking through the linker output file for symbols with particular names indicating they are constructor functions". So it's used to make linking possible.

我尝试的下一件事情是获取源代码.您可以在此处浏览代码 https://code.woboq.org/gcc/gcc /collect2.c.html .问题在于它并没有真正的帮助.但是我注意到用collect2 fork_execute函数来调用ld.您可以深入研究fork_execute,以了解它将分叉(在派生程序中执行新程序)并等待其完成.因为fork和exec都是系统调用(快速地说-系统调用是应用程序与系统通信的方式/功能).我决定尝试一下.

Next thing that I tried is getting through source code. You can browse code here https://code.woboq.org/gcc/gcc/collect2.c.html . The problem is that it wasn't really helpful. But I noticed that collect2 fork_execute function to invoke ld. You can deep dive into fork_execute to find out that it will fork (execute a new program in the forked program) and wait for it to finish. Because both forks and execs are system calls (to put it quickly - system calls are the way/functions the application uses to communicate with a system). I decided to give it a try.

所以我做了一个简单的程序,不需要任何编译(它已经编译到目标文件了-所以gcc要做的所有事情都是链接).

So I made the simple program that doesn't require any compilation (it's already compiled to object file - so everything that gcc have to do is linking).

[Alex@Normandy tmp]$ gcc hello.c.s  -o hello_gcc
[Alex@Normandy tmp]$ ./hello_gcc 
Hello, World!

然后我将strace与以下选项一起使用:

Then I use strace with following options:

  • -o forked.log将输出保存到fork.log
  • -s 1024少于1024个字符的变量不会被截断(默认32个字符还不够)
  • -f-在分叉的进程上启用strace
  • -e trace=/exec-过滤系统调用,因此仅显示以exec开头的那些
  • -o forked.log save the output to forked.log
  • -s 1024 variables shorter than 1024 chars are not truncated (default 32 was not enough)
  • -f - enables strace on forked processes
  • -e trace=/exec - filter system calls so only ones starting with exec are shown

以下是最终输出.

[Alex@Normandy tmp]$ strace -o forked.log -s 1024 -f -e trace=/exec gcc hello.c.s  -o hello_gcc
[Alex@Normandy tmp]$ grep 'ld' forked.log 
2153  execve("/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2", ["/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2", "--build-id", "--no-add-needed", "--eh-frame-hdr", "--hash-style=gnu", "-m", "elf_x86_64", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o", "hello_gcc", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64", "-L/lib/../lib64", "-L/usr/lib/../lib64", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../..", "/tmp/ccyl36jf.o", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o"], 0x17b9da0 /* 61 vars */) = 0
2154  execve("/usr/bin/ld", ["/usr/bin/ld", "--build-id", "--no-add-needed", "--eh-frame-hdr", "--hash-style=gnu", "-m", "elf_x86_64", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o", "hello_gcc", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64", "-L/lib/../lib64", "-L/usr/lib/../lib64", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../..", "/tmp/ccyl36jf.o", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o"], 0x7fff14226a98 /* 61 vars */) = 0

所以使用的ld命令是

/usr/bin/ld --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello_gcc /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. /tmp/ccyl36jf.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o

那么f ***是什么制成的?好吧,所有选项都可以在手册中找到.这是分解后的输出.

So what the f*** was made? Well, all options can be found in the manual. Here is decomposed output.

  • /usr/bin/ld-链接器程序
  • --build-id-将build-id添加到二进制文件.在我的系统默认值是sha1.
  • --no-add-needed-它是--no-copy-dt-needed-entries的已取消域名-它与ELF中的DT_NEEDED标签相连,如果我正确理解,则意味着不会从输入库中复制DT_NEEDED标签
  • --eh-frame-hdr-请求创建".eh_frame_hdr""部分和ELF"PT_GNU_EH_FRAME";段标题."意味着什么.
  • --hash-style=gnu-设置链接程序的哈希表的类型."默认值为sysv,但是有一种新的格式gnu.二进制文件也可以具有两种格式的哈希表.
  • -m elf_x86_64-链接器模拟(使x86_64的elf类型二进制)
  • -dynamic-linker /lib64/ld-linux-x86-64.so.2-设置预期的动态链接器的名称
  • -o hello_gcc-设置输出二进制文件
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o-在实际程序主体之前之前运行的代码
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o-在实际程序的主程序中之前运行的代码
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o-在实际程序的主程序中之前运行的代码
  • -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5-其他库搜索路径
  • -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64-其他库搜索路径
  • -L/lib/../lib64-其他库搜索路径
  • -L/usr/lib/../lib64-其他库搜索路径
  • -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../..-其他库搜索路径
  • /tmp/ccyl36jf.o-这是具有主要功能的实际程序(二进制对象)
  • -lgcc--l选项-将namespec指定的归档文件或目标文件添加到要链接的文件列表中".在这种情况下,它就是gcc.
  • --as-needed-启用按需"功能检查是否需要在特定点上跟随库(命名空间?)的模式
  • -lgcc_s-添加gcc_s请注意,仅在此刻确实需要时.
  • --no-as-needed-禁用按需"检查是否需要在特定点上跟随库(命名空间?)的模式
  • -lc-标准C名称空间/库
  • -lgcc-此lib应该已经设置.此选项与以前的使用之间可能会有所不同.
  • --as-needed-设置按需模式".此选项与以前的使用之间可能会有所不同.
  • -lgcc_s-已描述.此选项与以前的使用之间可能会有所不同.
  • --no-as-needed-禁用按需模式".
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o-程序完成时运行的其他代码
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o-程序完成时运行的其他代码.
  • /usr/bin/ld - linker program
  • --build-id - add build-id to binary. In my system default it is sha1.
  • --no-add-needed - it is depracaceted name for --no-copy-dt-needed-entries - it is connected with DT_NEEDED tags inside ELF, if I get that correctly it means that DT_NEEDED tag won't be copied from input libraries.
  • --eh-frame-hdr - "Request creation of ".eh_frame_hdr" section and ELF "PT_GNU_EH_FRAME" segment header." Whatever that means.
  • --hash-style=gnu - "Set the type of linker's hash table(s)." Default is sysv, but there is a newer format gnu. Binary can also have a hash table(s) in both formats.
  • -m elf_x86_64 - linkers emulates (makes elf type binary for x86_64)
  • -dynamic-linker /lib64/ld-linux-x86-64.so.2 - set name of expected dynamic linker
  • -o hello_gcc - set output binary
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o - code that is run before main of actual program
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o- code that is run before main of actual program
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o - code that is run before main of actual program
  • -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 - additional library search path
  • -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 - additional library search path
  • -L/lib/../lib64 - additional library search path
  • -L/usr/lib/../lib64 - additional library search path
  • -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. - additional library search path
  • /tmp/ccyl36jf.o - this is actual program (binary object) with it's main function
  • -lgcc - -l option - "Add the archive or object file specified by namespec to the list of files to link." In that case it is gcc.
  • --as-needed - enable "as-needed" mode that checks if on particular point following library (namespace?) is needed
  • -lgcc_s - add gcc_s note that only if it's really needed at this moment.
  • --no-as-needed - disable "as-needed" mode that checks if on particular point following library (namespace?) is needed
  • -lc- standard C namespace/library
  • -lgcc - this lib should be already set. There might be something between this and previous usage of this option.
  • --as-needed - set "as-needed mode. There might be something between this and previous usage of this option.
  • -lgcc_s - already described. There might be something between this and previous usage of this option.
  • --no-as-needed -- disable "as-needed mode".
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o - additional code that run when program finish
  • /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o - additional code that run when program finish.

有关以下内容的更多信息:crt1.ocrti.ocrtbegin.ocrtend.ocrtn.o-它们是启动文件,初始化文件,构造函数,析构函数和终结文件(根据Karim Yaghmour的《构建嵌入式Linux系统》).

More about: crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o - they are startup, initialization, constructor, destructor and finalization files (according to Building Embedded Linux Systems By Karim Yaghmour).

在撰写此答案时,我也发现"了一个答案.您可以使用-v选项调用gcc,它将返回 COLLECT_GCC_OPTIONS ,与调用的ld

During writing this answer I also "discovered" that you can invoke gcc with -v option and it will return COLLECT_GCC_OPTIONS, that is identical to invoked ld

COLLECT_GCC_OPTIONS='-v' '-o' 'hello_gcc' '-mtune=generic' '-march=x86-64'
 /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello_gcc /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. hello_gcc.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o

不过,如果您想确保100%调用ld的方式-strace是最好的选择.

Still, if you want to be sure for 100% how ld was invoked - the strace is your best bet.

最后,请注意,我使用Enterprise Linux v7和v8系统检查我是否正确.它们都使用x86_64架构,在不同的体系结构上结果可能会有所不同.

Lastly, note that I used Enterprise Linux v7 and v8 system to check if I'm right. Both of them uses the x86_64 arch, and the results might be different on different architectures.

这篇关于gcc使用的实际默认链接描述文件和设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆