• ld script初探[2]


    a、Q&A

    Q:为什么编出来的应用肯定是在用户地址空间运行,而内核编出来的代码却一定是运行在内核空间?

    A:链接器(Linker):目的是描述输入文件的sections是如何映射到输出文件中,并控制输出文件的内存排列。

    而且ld就是使用这个缺省的script内置在链接器中。

    b、链接脚本具体实践
    链接脚本中无论是输出文件还是输入文件,主要数据是文件中的各种段,把输入文件中的段称为输入段(Input Sections),输出文件中的段称为
    输出段(Output Sections)。
    一般链接脚本名都以lds作为扩展名,ld script

    ld script语法:
    1.语句之间使用分号";"作为分隔符,但是对于命令语句来说也可以使用换行来结束该语句。
    2.脚本文件中使用到的文件名、格式名或段名等凡包含";"或其他的分隔符的,都要使用双引号将该名字全称引用起来。

    实践:hello.c

    #include <stdio.h>

    int main()
    {
    printf("Hello World\n");
    return 0;
    }

    预处理:gcc -E hello.c -o hello.i
    编译:gcc -S hello.i -o hello.s
    汇编:as hello.s -o hello.o
    链接:ld -static -verbose /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbeginT.o -
    L/usr/lib/gcc/i386-redhat-linux/4.1.2 -L/usr/lib -L/lib hello.o -start-group -lgcc -lgcc_eh -lc -end-group
    /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o /usr/lib/crtn.o > 1.txt

    1.txt

    GNU ld version 2.17.50.0.6-9.el5 20061020
    Supported emulations:
    elf_i386
    i386linux
    using internal linker script:
    ==================================================
    /* Script for -z combreloc: combine and sort reloc sections */
    OUTPUT_FORMAT("elf32-i386", "elf32-i386",
    "elf32-i386") ;输出文件使用的BFD格式
    OUTPUT_ARCH(i386) ;设置输出文件的machine architecture
    ENTRY(_start) ;将符号SYMBOL的值设置成入口地址
    SEARCH_DIR("/usr/i386-redhat-linux/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); ;定
    义搜索路径
    SECTIONS
    {
    /* Read-only sections, merged into text segment: */
    PROVIDE (__executable_start = 0x08048000); ;PROVIDE关键字用于定义这类符号:在目标文件内被引用,但没有在任何目标文件内被定义
    的符号
    . = 0x08048000 + SIZEOF_HEADERS; ;当前地址为0x08048000 + SIZEOF_HEADERS
    .interp : { *(.interp) }
    .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.*)
    }
    .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.*)
    }
    .rel.plt : { *(.rel.plt) }
    .rela.plt : { *(.rela.plt) } ;包含相关的段
    .init :
    {
    KEEP (*(.init)) ;KEEP()强制连接器保留一些特定的section
    } =0x90909090
    .plt : { *(.plt) }
    .text :
    {
    *(.text .stub .text.* .gnu.linkonce.t.*)
    KEEP (*(.text.*personality*))
    /* .gnu.warning sections are handled specially by elf32.em. */
    *(.gnu.warning)
    } =0x90909090 ;填充0x9090
    .fini :
    {
    KEEP (*(.fini))
    } =0x90909090
    PROVIDE (__etext = .); ;PROVIDE关键字用于定义这类符号:在目标文件内被引用,但没有在任何目标文件内被定义的符号
    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) }
    . = DATA_SEGMENT_RELRO_END (12, .);
    .got.plt : { *(.got.plt) }
    .data :
    {
    *(.data .data.* .gnu.linkonce.d.*)
    KEEP (*(.gnu.linkonce.d.*personality*))
    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) }
    /DISCARD/ : { *(.note.GNU-stack) }
    }


    ==================================================
    attempt to open /usr/lib/crt1.o succeeded
    /usr/lib/crt1.o
    ........
    /usr/lib/crtn.o

    c、参考链接:
    http://blog.chinaunix.net/space.php?uid=20433875&do=blog&id=1680446
    http://www.52rd.com/Blog/Detail_RD.Blog_imjacob_19486.html
    http://blog.chinaunix.net/space.php?uid=10678279&do=blog&id=2936584
    http://hi.baidu.com/dljaye/blog/item/7b56fb9be84909b9c9eaf486.html
    http://hi.chinaunix.net/?20792635/viewspace-35408
    http://topic.csdn.net/u/20090812/16/d3d9cca2-78d3-4e97-afa4-79fafa439ccc.html
    http://www.linuxeden.com/forum/thread-61470-1-1.html
    程序员自我修养:使用ld链接脚本

  • 相关阅读:
    构建之法阅读笔记06
    构建之法阅读笔记05
    人月神话阅读笔记02
    人月神话阅读笔记01
    构建之法阅读笔记04
    学习进度09
    描绘用户场景并将典型用户和用户场景描述
    学习进度08
    第一冲刺阶段工作总结11
    第一冲刺阶段工作总结10
  • 原文地址:https://www.cnblogs.com/moonflow/p/2312493.html
Copyright © 2020-2023  润新知