Chinaunix首页 | 论坛 | 博客
  • 博客访问: 173625
  • 博文数量: 47
  • 博客积分: 992
  • 博客等级: 准尉
  • 技术积分: 565
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-08 21:57
文章分类

全部博文(47)

文章存档

2019年(1)

2018年(1)

2017年(1)

2014年(6)

2013年(1)

2012年(2)

2011年(35)

我的朋友

分类: LINUX

2011-06-13 18:54:28

LinuxKernel110609: ld注记


Email:    zcatt@163.com
Blog    http://zcatt.blog.chinaunix.net
 
声明
仅限学习交流,禁止商业用途。转载需注明出处。
文中直接引用了[1]和[2]的内容. 文中不再特别明示.

版本记录
Date        Ver        Note
2011-06-13    0.1        Draft.  zcatt, Beijing


ld是GNU的linker. linker的功能就是将obj, 或许还有lib, 组装成可执行文件或lib, 特别的, 还可以生成其它的特殊形式, 例如多个obj组装成一个obj(relocatable).

1. ld的用法
=====================

一个例子,
    ld -T output.ld  /lib/crt0.o hello.o -lc -o output
crt0.o, hello.o和libc.a会链接生成output, 使用output.ld做为链接脚本(linker script)文件.

对于gcc间接调用ld的情况, 要将选项传递给ld,可以使用"-Wl,"后给逗号间隔的选项, 例如,
           gcc -Wl,--start-group foo.o bar.o -Wl,--end-group

ld的输入选项比较多, 详细可参考man, 这里罗列几个常用的.

@file
    Read command-line options from file.

-e entry
--entry=entry
    Use entry as the explicit symbol for beginning execution of your program, rather than the default entry point.

-l namespec
--library=namespec
    On systems which support shared libraries, ld may also search for files other than libnamespec.a. Specifically, on ELF and SunOS systems, ld will search a directory for a library called libnamespec.so before searching for one called libnamespec.a.

-L searchdir
--library-path=searchdir
    Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts. You may use this option any number of times.

-M
--print-map
    Print a link map to the standard output.

-o output
--output=output
    Use output as the name for the program produced by ld; if this option is not specified, the name a.out is used by default.

-q
--emit-relocs
    Leave relocation sections and contents in fully linked executables. Post link analysis and optimization tools may need this information in order to perform correct modifications of executables. This results in larger executables.
    This option is currently only supported on ELF platforms.

-r
--relocatable
    Generate relocatable output—i.e., generate an output file that can in turn serve as input to ld. This is often called partial linking

-T scriptfile
--script=scriptfile
    Use scriptfile as the linker script.

-Bdynamic
-dy
-call_shared
    Link against dynamic libraries. This is only meaningful on platforms for which shared libraries are supported.

-Bstatic
-dn
-non_shared
-static
    Do not link against shared libraries. This is only meaningful on platforms for which shared libraries are supported.

-Map=mapfile
    Print a link map to the file mapfile.

-nostdlib
    Only search library directories explicitly specified on the command line. Library directories specified in linker scripts (including linker scripts specified on the command line) are ignored.

-shared
-Bshareable
    Create a shared library.

-section-start=sectionname=org
    Locate a section in the output file at the absolute address given by org
-Tbss=org
-Tdata=org
-Ttext=org
    Same as --section-start, with .bss, .data or .text as the sectionname.

2.Linker Script
=====================

ld加工输入的obj和lib文件, 最终生成一个output.
obj是由section组成的, 我们称ld输入obj中的section为input section, 而output中的section为output section.
section按照所包含内容可以分为3类. section的内容要装载到mem中, 则这样的section称作loadable; section没有内容需要装载到mem, 仅需在mem中占据一定空间(也包括清零空间), 则这样的section称作allocatable; 不是上述两类的, 也就是不必载入mem的section是第3类, 通常包括例如调试信息等. 通常程序的有效部分是loadable和allocatable.
每个section有两个地址: VMA, virtual memory address,和LMA, load memory address. VMA是section在mem中运行是所处的地址, 而LMA则是section载入mem是的地址. 有时LMA和VMA并不相同, 需要在执行section前, 将section从LMA搬移到VMA.

input section被ld加工成output section, 那么ld如何将input section中的内容变换并按照需求的地址格局(layout)放置到output中呢? linker script就是实现这个任务的. 你可以写自己的linker script, 让ld按照需求的地址格局生成output. 在上文的例子中可以看到'-T'用于指定linker script文件.

一个简单例子,

    ENTRY(__start)

    SECTIONS
     {
       . = 0x10000;
       .text : { *(.text) }
       . = 0x8000000;
       .data : { *(.data) }
       .bss : { *(.bss) }
     }

ENTRY(__start)
ENTRY()等同于命令行参数'-e', 指明入口点. 默认的是.text section的第一个字节, 或地址0.

. = 0x10000
'.'是个特殊的值, 代表的是当前地址. 这句是说从0x10000地址开始放置section.

.text : { *(.text) }
'.'text是output section的名字. '*(.text)'代表所有输入文件的'.text' sections.
后面.data被放到0x8000000地址处, .bss放到.data后面.

linker script的主体是SECTIONS. SECTIONS又由sections command组成

     SECTIONS
     {
       sections-command
       sections-command
       ...
     }

section command的具体语法,

     section [address] [(type)] :
       [AT(lma)]
       [ALIGN(section_align)]
       [SUBALIGN(subsection_align)]
       [constraint]
       {
         output-section-command
         output-section-command
         ...
       } [>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp]

其中, section是section name, address是VMA address, lma是LMA address.
如果output section name是'/DISCARD/', 则标明这个output section对应的input section可以被丢弃, 不写入output中.

每个output section都有一个type. type的类型有,

NOLOAD
    The section should be marked as not loadable, so that it will not be loaded into memory when the program is run.

DSECT
COPY
INFO
OVERLAY
    These type names are supported for backward compatibility, and are rarely used. They all have the same effect: the section should be marked as not allocatable, so that no memory is allocated for the section when the program is run.

一个实际中的例子, 取自 linuxKernel 2.6.31/arch/x86/boot/setup.ld

/*
 * setup.ld
 *
 * Linker script for the i386 setup code
 */
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)

SECTIONS
{
    . = 0;
    .bstext        : { *(.bstext) }
    .bsdata        : { *(.bsdata) }

    . = 497;
    .header        : { *(.header) }
    .entrytext    : { *(.entrytext) }
    .inittext    : { *(.inittext) }
    .initdata    : { *(.initdata) }
    __end_init = .;

    .text        : { *(.text) }
    .text32        : { *(.text32) }

    . = ALIGN(16);
    .rodata        : { *(.rodata*) }

    .videocards    : {
        video_cards = .;
        *(.videocards)
        video_cards_end = .;
    }

    . = ALIGN(16);
    .data        : { *(.data*) }

    .signature    : {
        setup_sig = .;
        LONG(0x5a5aaa55)
    }


    . = ALIGN(16);
    .bss        :
    {
        __bss_start = .;
        *(.bss)
        __bss_end = .;
    }
    . = ALIGN(16);
    _end = .;

    /DISCARD/ : { *(.note*) }

    . = ASSERT(_end <= 0x8000, "Setup too big!");
    . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
    /* Necessary for the very-old-loader check to work... */
    . = ASSERT(__end_init <= 5*512, "init sections too big!");

}



REF
=====================
1. Documentation for binutils 2.21,
2. linux kernel 2.6.31


Locations of visitors to this page
阅读(709) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~