`

解释一个ld.script文件

 
阅读更多
本文详细解释一个 ld.script 文件
可以通过以下命令查看系统默认使用的链接脚本:
$ ld -verbose #输出如下
GNU ld (GNU Binutils for Ubuntu) 2.20.1-system.20100303
  Supported emulations:
   elf_i386
   i386linux
   elf_x86_64
   elf_l1om
using internal linker script:
==================================================
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
	      "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/usr/i486-linux-gnu/lib32"); SEARCH_DIR("/usr/local/lib32"); 
SEARCH_DIR("/lib32"); SEARCH_DIR("/usr/lib32"); SEARCH_DIR("/usr/i486-linux-gnu/lib");
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", 0x08048000)); 
       . = SEGMENT_START("text-segment", 0x08048000) + 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) }
  .rel.dyn        :
    {
      *(.rel.init)
      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
      *(.rel.fini)
      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
      *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
      *(.rel.ctors)
      *(.rel.dtors)
      *(.rel.got)
      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
      *(.rel.ifunc)
    }
  .rel.plt        :
    {
      *(.rel.plt)
      PROVIDE_HIDDEN (__rel_iplt_start = .);
      *(.rel.iplt)
      PROVIDE_HIDDEN (__rel_iplt_end = .);
    }
  .init           :
  {
    KEEP (*(.init))
  } =0x90909090
  .plt            : { *(.plt) *(.iplt) }
  .text           :
  {
    *(.text.unlikely .text.*_unlikely)
    *(.text .stub .text.* .gnu.linkonce.t.*)
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  } =0x90909090
  .fini           :
  {
    KEEP (*(.fini))
  } =0x90909090
  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.*) }
  /* 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.*) }
  /* 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(.init_array.*)))
     KEEP (*(.init_array))
     PROVIDE_HIDDEN (__init_array_end = .);
  }
  .fini_array     :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(.fini_array))
    KEEP (*(SORT(.fini_array.*)))
    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* .gnu.linkonce.d.rel.ro.*) }
  .dynamic        : { *(.dynamic) }
  .got            : { *(.got) *(.igot) }
  . = DATA_SEGMENT_RELRO_END (12, .);
  .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 ? 32 / 8 : 1);
  }
  . = ALIGN(32 / 8);
  . = ALIGN(32 / 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_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) }
  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

==================================================


下面逐句解释。

 

OUTPUT_FORMAT("elf32-i386", "elf32-i386",
	      "elf32-i386")
OUTPUT_ARCH(i386)

OUTPUT_FORMAT 和 OUTPUT_ARCH 都是 ld 脚本的保留字命令。OUTPUT_FORMAT 说明输出二进制文件的格式。OUTPUT_ARCH 说明输出文件系统平台。

ENTRY(_start)

ENTRY 命令的作用是,将后面括号中的符号值设置成入口地址。入口地址(entry point)的定义是这样的──进程执行的第一条用户空间的指令在进程地址空间中的地址。

ld 有多种方法设置进程入口地址,通常它按以下顺序:(编号越前, 优先级越高)
1, ld 命令行的-e选项
2, 连接脚本的 ENTRY(SYMBOL) 命令
3, 如果定义了 start 符号, 使用 start 符号值
4, 如果存在 .text section, 使用 .text section 的第一字节的位置值
5, 使用值 0

 

SEARCH_DIR("/usr/i486-linux-gnu/lib32");

设置链接时搜寻库文件目录.

 

SECTIONS
{

然后,接下来是一大段的 SECTIONS,对应的右大括号直到脚本的末尾。
SECTIONS 命令告诉 ld 如何把输入文件的 sections 映射到输出文件的各个 section:即是如何将输入 section 合为输出 section;如何把输出 section 放入程序地址空间 (VMA) 和进程地址空间 (LMA) 。该命令格式如下:
SECTIONS
{
….
}

/* Read-only sections, merged into text segment: */
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); 

PROVIDE 定义的变量 如果源文件中已经定义值 那么用源文件中的,如果没有定义则用脚本中定义的。
并设定该变量的值为0x08048000

. = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS;

这句把定位器符号置为 0x08048000 + SIZE_HEADERS(若不指定,则该符号的初始值为 0)。
SIZE_HEADERS为输出文件的文件头.
. 是一个特殊的符号,它是定位器,一个位置指针,指向程序地址空间内的某位置(或某section内的偏移,如果它在SECTIONS命令内的某section描述内),该符号只能在SECTIONS命令内使用。
  .rel.dyn        :
    {
      *(.rel.init)
      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
      *(.rel.fini)
      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
      *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
      *(.rel.ctors)
      *(.rel.dtors)
      *(.rel.got)
      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
      *(.rel.ifunc)
    }
  .rel.plt        :
    {
      *(.rel.plt)
      PROVIDE_HIDDEN (__rel_iplt_start = .);
      *(.rel.iplt)
      PROVIDE_HIDDEN (__rel_iplt_end = .);
    }
以上这些段主要用于重定位.具体的内容还需进一步学习.先不做介绍.

  .init           :
  {
    KEEP (*(.init))
  } =0x90909090
  .plt            : { *(.plt) *(.iplt) }
  .text           :
  {
    *(.text.unlikely .text.*_unlikely)
    *(.text .stub .text.* .gnu.linkonce.t.*)
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  } =0x90909090

.init将在下文与.fini一起介绍.
.text : 表示text段开始.
*(.text) 将所有(*符号代表任意输入文件)输入文件的.text section合并成一个.text section, 该section的地址由定位器符号的值指定, 即0x08048000.
*(.text.unlikely .text.*_unlikely)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em.  */
*(.gnu.warning)
  .fini           :
  {
    KEEP (*(.fini)) #
KEEP()强制连接器保留一些特定的section  
  } =0x90909090

ELF文件中定义了 .init 和 .fini 两个特殊的段,其中 .init 段中的代码会在main之前被执行,.fini 段中的代码会在main退出之后被执行.默认用NOP(0x90)字段进行填充.
  PROVIDE (__etext = .);
  PROVIDE (_etext = .);
  PROVIDE (etext = .);

__etext=.  _etext = .  etext=.; 我们看到,很多变量都定义成等于这个 . 符,实际上这个符号所代表的值是在变化的,随着越往后走,值越增加,根据前面填充的多少自动往后加。即指定当前地址值为代码段结束位置.
这里就定义了一个 etext 符号,当目标文件内引用了 etext 符号,却没有定义它时,etext 符号对应的地址被定义为 .text section 之后的第一个字节的地址。
  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
  .rodata1        : { *(.rodata1) }
 
数据段终于来到了,意思很容易理解的了(用于只读数据段)。
 /* 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));
如注释所述用于地址调整,为数据段作相应的地址对齐.
  /* Thread Local Storage sections  */
  .tdata      : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
  .tbss          : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
正如注释所描述,这两个段用于线程的局部数据段(包括data及bss)

CONSTRUCTORS 是一个保留字命令。与 c++ 内的(全局对象的)构造函数和(全局对像的)析构函数相关。
  .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))
  }

对于支持任意section名的目标文件格式,比如COFF、ELF格式,GNU C++将全局构造和全局析构信息分别放入 .ctors section 和 .dtors section 内
当连接器生成的目标文件格式不支持任意section名字时,比如说ECOFF、XCOFF格式,连接器将通过名字来识别全局构造和全局析构,对于这些文件格式,连接器把与全局构造和全局析构的相关信息放入出现 CONSTRUCTORS 关键字的输出section内。

一般来说,GNU C++在函数__main内安排全局构造代码的运行,而__main函数被初始化代码(在main函数调用之前执行)调用。

  .got            : { *(.got) *(.igot) }
  . = DATA_SEGMENT_RELRO_END (12, .);
  .got.plt        : { *(.got.plt)  *(.igot.plt) }

意义不明,需进一步探究.
_edata = .; PROVIDE (edata = .);

意义与前面的 etext 类似。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 ? 32 / 8 : 1);
  }
  . = ALIGN(32 / 8);
  . = ALIGN(32 / 8);
  _end = .; PROVIDE (end = .);
  . = DATA_SEGMENT_END (.);

BSS段开始了。
COMMON 这个保留字的意义:
通用符号(common symbol)的输入section:
在许多目标文件格式中,通用符号并没有占用一个section。连接器认为:输入文件的所有通用符号在名为COMMON的section内。
上例中将所有输入文件的所有通用符号放入输出.bss section内。

这里,定义了几个重要的符号
__bss_start = .;
_end = .;
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_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) }
  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }

  这里主要包含代码的调试信息,用于调试时使用.包括一些行号信息及符号表等.
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
DISCARD关键字用于将指定段舍弃,不出现在输出文件中.

余下的这几个意义也类似,看英文注释应该能明白。

对初步编译出来的一个二进制文件进行 nm 解析(nm -n a.out),得到如下内容:

         U _IO_getc@@GLIBC_2.0
         w _Jv_RegisterClasses
         U __ctype_b_loc@@GLIBC_2.3
         U __errno_location@@GLIBC_2.0
         w __gmon_start__
         U __isoc99_sscanf@@GLIBC_2.7
         U __libc_start_main@@GLIBC_2.0
         U __stack_chk_fail@@GLIBC_2.4
         U exit@@GLIBC_2.0
         U fclose@@GLIBC_2.1
         U feof@@GLIBC_2.0
         U fgets@@GLIBC_2.0
         U fopen@@GLIBC_2.1
         U printf@@GLIBC_2.0
         U sprintf@@GLIBC_2.0
         U strerror@@GLIBC_2.0
         U strtol@@GLIBC_2.0
         U vfprintf@@GLIBC_2.0
080485a8 T _init
08048700 T _start
08048730 t __do_global_dtors_aux
08048790 t frame_dummy
080487b4 T die
080487e7 T print_name_pid
08048904 T print_maps
08048be3 T parse_pid
08048c3a T main
08048cc0 T __libc_csu_fini
08048cd0 T __libc_csu_init
08048d2a T __i686.get_pc_thunk.bx
08048d30 t __do_global_ctors_aux
08048d5c T _fini
08048d78 R _fp_hw
08048d7c R _IO_stdin_used
08048e80 r __FRAME_END__
08049f0c d __CTOR_LIST__
08049f0c d __init_array_end
08049f0c d __init_array_start
08049f10 d __CTOR_END__
08049f14 d __DTOR_LIST__
08049f18 D __DTOR_END__
08049f1c d __JCR_END__
08049f1c d __JCR_LIST__
08049f20 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
0804a044 D __data_start
0804a044 W data_start
0804a048 D __dso_handle
0804a04c A __bss_start
0804a04c A _edata
0804a04c B stderr@@GLIBC_2.0
0804a050 b completed.7021
0804a054 b dtor_idx.7023
0804a058 A _end



可以看到,所有的地址全是从 0x08048000 开始的。

U表示该符号未定义,主要是动态链接库中的符号,在目标文件加载入内存的时候再进行解析.

w表示该符号为弱符号

         U _IO_getc@@GLIBC_2.0
         w _Jv_RegisterClasses
         U __ctype_b_loc@@GLIBC_2.3
         U __errno_location@@GLIBC_2.0


         w __gmon_start__


         U __isoc99_sscanf@@GLIBC_2.7
         U __libc_start_main@@GLIBC_2.0
         U __stack_chk_fail@@GLIBC_2.4
         U exit@@GLIBC_2.0
         U fclose@@GLIBC_2.1
         U feof@@GLIBC_2.0
         U fgets@@GLIBC_2.0
         U fopen@@GLIBC_2.1
         U printf@@GLIBC_2.0
         U sprintf@@GLIBC_2.0
         U strerror@@GLIBC_2.0
         U strtol@@GLIBC_2.0
         U vfprintf@@GLIBC_2.0

 

两个个起始符号(T表示在text段中)

080485a8 T _init
08048700 T _start

 

几个函数都在代码段内

08048730 t __do_global_dtors_aux
08048790 t frame_dummy
080487b4 T die
080487e7 T print_name_pid
08048904 T print_maps
08048be3 T parse_pid
08048c3a T main

 

栈底地址果然是在 start 下方 0x4000 处
800fc000 T stack

(A 表示绝对不变)

0804a04c A __bss_start
0804a04c A _edata


0804a058 A _end

 

全局构造和析构变量段(D表示在已初始化过的数据段中)

08049f0c d __CTOR_LIST__
08049f0c d __init_array_end
08049f0c d __init_array_start
08049f10 d __CTOR_END__
08049f14 d __DTOR_LIST__
08049f18 D __DTOR_END__
08049f1c d __JCR_END__
08049f1c d __JCR_LIST__
08049f20 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
0804a044 D __data_start
0804a044 W data_start
0804a048 D __dso_handle

 

还有一个是用 B 标记的,表示在未初始化的数据段中

0804a04c B stderr@@GLIBC_2.0
0804a050 b completed.7021
0804a054 b dtor_idx.7023

上面符号类型可以查看nm命令的man帮助文档.

结合这些数据,去理解前面的 ld.script 的讲解,会有一个清晰的印象。
分享到:
评论

相关推荐

    Link-Script语法/ HighTec用户手册/ 链接脚本

    The Linker Script File .ld 文件 ,链接脚本说明,第十九章介绍所有的ld脚本相关说明,对于链接脚本解析与阅读有很好的参考作用。 例如: CORE_ID、FLAGS、KEEP、REGION_MAP、AT等指令详细说明及案例。

    json-ld:用于RDF.rb的Ruby JSON-LD读写器

    JSON-LD读取器/写入器 用于和完全处理器的读取器/写入器。 此外,此gem实现了 。...这个gem实现了一个优化的流阅读器,该阅读器用于从格式为JSON-LD的大型数据集转储中生成RDF。 此类文档必须与JSON-LD流配置文件相对应

    linux从入门到精通.chm

    E.6.17 我安装Linux时没有遇到错误, 但是在重启动时, 我只能得到L, LI 和其他一个项目. 为什么? E.7 使用Red Hat Linux E.7.1 我不能运行我编译的任何程序, 因为 我得到一个"command not found"出错信息. 我在目录...

    Using ld The GNU linker version 2

    GNU ld是链接器,ld实际并...所有的链接过程都是由LD脚本控制的,写这个脚本的语言称为 linker command language,LD脚本的最主要的功能是描述如何将输入文件映射到输出文件以及输出文件的存储布局(memory layout)。

    openredir:通过 LD_PRELOAD 重定向文件打开操作

    打开目录 通过 LD_PRELOAD 重定向文件打开操作

    uboot链接脚本

    每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名)控制. 链接脚本主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空间内的布局. 但你也可以用连接...

    《Linux从入门到精通》

    E.6.17 我安装Linux时没有遇到错误, 但是在重启动时, 我只能得到L, LI 和其他一个项目. 为什么? E.7 使用Red Hat Linux E.7.1 我不能运行我编译的任何程序, 因为 我得到一个"command not found"出错信息. 我在目录...

    Linux从入门到精通

    E.6.17 我安装Linux时没有遇到错误, 但是在重启动时, 我只能得到L, LI 和其他一个项目. 为什么? E.7 使用Red Hat Linux E.7.1 我不能运行我编译的任何程序, 因为 我得到一个"command not found"出错信息. 我在目录...

    2005详细介绍Linux从入门到精通

    E.6.17 我安装Linux时没有遇到错误, 但是在重启动时, 我只能得到L, LI 和其他一个项目. 为什么? E.7 使用Red Hat Linux E.7.1 我不能运行我编译的任何程序, 因为 我得到一个"command not found"出错信息. 我在目录...

    Linux指令一周通 (技术图书大系).azw3

    4.36 uucp 指令:将特定文件复制到另一个特定系统 4.37 uulog指令:显示uucp记录信息 4.38 uuname指令:显示uucp远端主机 4.39 uustat指令:显示uucp状态 4.40 uux指令:在远端的uucp主机上运行指令 4.41 wall指令:...

    Linker Script

    链接脚本使用文档Linker script,详细说明链接文件使用方法

    最新版busybox-1.19.4

    8、创建一个空的mdev.conf文件,在挂载根文件系统时会用到的 [root@Sure etc]# touch mdev.conf 9、从本机拷贝passwd、shadow、group文件。 [root@Sure etc]# cp /etc/passwd . [root@Sure etc]# cp /etc/...

    k-means_old-faithful-master6.zip

    代码的主要用处是从文本文档中读取数据,使用k-means算法进行聚类分析,运行KMeans_script.m文件即可,该文件中k为聚类中心个数,filename为读取的文件名。

    文本文件类扩展名.txt

    收集的一千多个文本文件扩展名: 1c 1f 1st 2 3 3pc 4 4gl 4th 5 51 6 68k 7 8 800 850 9 a a51 a75 aas abap abl abp abv ac acl acpi act act2000 ad ada adb adm ado ads ...

    brcode:用于Rust的PIX BR代码解析器

    BR代码一个用于解析并发出板条箱。重要变化对于BrCode字段,版本1.2 BrCode休息。 修复了model::BrCode字段的initiation_method命名。用法[ dependencies ]brcode = " 1.4.2 "从源代码构建安装 。 为macos和ios文件...

    在晶心平台实作ROM patch技术分享

    网络上有GNU ld的使用文件,但是linker script的范例太少,尤其开发者需要撰写进阶的linker script,常常不知如何下手。  本篇文章我们分享如何实作ROM patch.使用晶心CPU建构的embedded system,一般具有CPU、外围...

    嵌入式系统/ARM技术中的在晶心平台实作ROM patch技术分享

    网络上有GNU ld的使用文件,但是linker script的范例太少,尤其开发者需要撰写进阶的linker script,常常不知如何下手。  本篇文章我们分享如何实作ROM patch.使用晶心CPU建构的embedded system,一般具有CPU、外围...

    computer-toolkit:计算机开发工具

    Trillek 计算机工具包Trillek电脑电脑开发工具 v0.2.0得到它下载适用于您的操作系统... 例如make CC=i686-w64-mingw32-gcc LD=i686-w64-mingw32-gcc BINEXT=.exe或make CC=i586-mingw32msvc-gcc LD=i586-mingw32msvc-gc

    minecraft:我的世界基岩服务器

    服务器将重新启动以进行维护,并在美国东部标准时间星期一,星期三和星期五的星期一备份世界文件。 在这段时间内登录可能会导致世界保存损坏! 安装注意事项 minecraft_bedrock.sh脚本包含用于保存更改并在启动时推...

    jquery Moblie入门—hello world的示例代码学习

    1、需要运行JQuery Mobile 移动应用页面,需要下载JQuery Mobile 3个相关插件文件(有多版本),jquery.mobile-1.2.0.min.css、jquery-1.8.3.min.js、jquery.mobile-1.2.0.min.js,JQuery Mobile官网地址:...

Global site tag (gtag.js) - Google Analytics