GNU-ld链接脚本浅析
【转】揪出gcc默认使用的ld链接脚本
【转】揪出gcc默认使用的ld链接脚本揪出gcc默认使用的ld链接脚本首先声明不是讲lds语法的在<<程序员的自我修养-链接装载与库>>一书中曾提到ld默认使用的链接脚本说默认在/usr/lib/ldscripts/下结果我找了半天没找到我的系统是fedora 8find / -name *lds* 找不到找script也找不到晕了后来查了下发现可以用ld -verbose查看默认的lds输出如下:GNU ld version 2.19.51.0.14-34.fc12 20090722Supported emulations:elf_i386i386linuxelf_x86_64using 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/i686-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 = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS;........后面略这就奇怪了,那么这个lds到底在哪呢?我们用find /usr/* |xargs grep "Script for -z combreloc"看看结果 Binary file /usr/bin/ld matches 可见已经集成到ld中了readelf -P --string-dump=.rodata ld便可以找到。
gcc编程环境基础4--ld命令和u-boot中的lds文件实例和简单实例分析
4.简单例子
5.简单脚本命令
6.对符号的赋值
7. SECTIONS命令
8. MEMORY命令
9. PHDRS命令
10. VERSION命令
11.脚本内的表达式
12.暗含的连接脚本
1.概论
--------------------------------------------------------------------------------
符号(symbol):每个目标文件都有符号表(SYMBOL TABLE),包含已定义的符号(对应全局变量和static变量和定义的函数的名字)和未定义符号(未定义的函数的名字和引用但没定义的符号)信息.
符号值:每个符号对应一个地址,即符号值(这与c程序内变量的值不一样,某种情况下可以把它看成变量的地址).可用nm命令查看它们. (nm的使用方法可参考本blog的GNU binutils笔记)
如果.data section的LMA为0x08050000,显然结果是j=2
如果.data section的LMA为0x08050004,显然结果是j=1
还可这样理解LMA:
.text section内容的开始处包含如下两条指令(intel i386指令是10字节,每行对应5字节):
jmp 0x08048285
-T选项用以指定自己的链接脚本,它将代替默认的连接脚本.你也可以使用<暗含的连接脚本>以增加自定义的链接命令.
以下没有特殊说明,连接器指的是静态连接器.
2.基本概念
--------------------------------------------------------------------------------
GNU ld使用手册
注意,如果连接器通过被编译器驱动来间接引用(比如 gcc), 那所有的连接器命令行选项前必 须加上前缀'-Wl' (或者能被特定编译器驱动接受的其他前缀),就像下面这样: gcc -Wl,--startgroup foo.o bar.o -Wl,--endgroup 这很重要,因为否则的话,编译器驱动程序会默认丢掉这些连接选项,产生一个错误的连接. 下面是关于被 GNU 连接器接受的常用命令行开关的一个列表: `-aKEYWORD' 这个选项在 HP/UX 兼容系统上被支持. 参数 KEYWORD 必须是下面字符串中的一个:`archive', `shared', or `default'. `-aarchive'在功能上跟`-Bstatic'相同,而另外两个关键字功能上跟 `-Bdynamic'相同. 这个选项可被多次使用. `-AARCHITECTURE' `--architecture=ARCHITECTURE' 在最近发行版本的'ld'中,这个选项只在 Intel 960 系列架构上有用. 在那种'ld'配置中,参数 ARCHITECTURE 确定 960 系列的某一特定架构,启用某些安全措施,并修改档案库的搜索 路径. 将来的'ld'发行版可能为其它架构系列支持相似的功能. `-b INPUT-formAT' `--format=INPUT-formAT' 'ld'可以被配置为支持多于一种的目标文件.如果你的'ld'以这种方式被配置,你可以使用'-b'选 项为输入目标文件指定二进制格式. 就算'ld'被配置为支持可选目标格式,你不必经常指定这 一项, 因为'ld'被配置为在每一台机子上把最常用的格式作为默认输入格式 . INPUT-formAT 是一个 字符串, 你可能在连接一个不常用的二进制格式文件时需要这个参数.你也可使用'-b'来显式切换格式 (在连接 不同格式的目标文件时),方法是在每一组特定格式的目标前使用'-b INPUT-formAT'. 缺省的格式是从环境变量'GNUTARGET'中得到的.你也可以从一个脚本中定义输入格式 ,使用 的命令是 'TARGET'. `-c MRI-COMMANDFILE' `--mri-script=MRI-COMMANDFILE' 为了跟 MRI 生产的连接器兼容,'ld'接受另一种用受限命令语言写成的脚本文件,通过选项'-c' 引入 MRI
gcc,ld
gcc,ldGCCgcc除了具备基本的c⽂件编译功能外,还把其它⼯具的功能也集成了进来,⽐如as的汇编功能,ld的链接功能。
因此,gcc也可以通过-Wa, option,将option传给汇编器as;也可以通过-Wl, option,将option传给链接器ld。
-N,gcc⼿册中没看到该选项,这是属于链接器ld的选项,gcc并没有。
该选项⽤于将text设为writable,见后⾯ld部分介绍。
-L,gcc⼿册中只有-Ldir⽤来设置搜索库⽂件的⽬录,单独⽤-L没看该选项基本选项-S,⼤写Compile only; do not assemble or link,输出汇编⽂件.s-c,⼩写Compile and assemble, but do not link.如果不加-c,那么gcc会直接编译+链接为可执⾏⽂件。
-o <file>Place the output into <file>-vPrint (on standard error output) the commands executed to run the stages of compilation. Also print the version number of the compiler driver program and of the preprocessorand the compiler proper. 下⾯为⼀个例⼦:sparc-elf-gcc.exe -v -c ../src/main.c -o ../obj/main.oReading specs from /cygdrive/c/SPE-C2.5/bin/../lib/gcc-lib/sparc-elf/3.2.3/specsConfigured with: ../gcc-3.2.3/configure --target=sparc-elf --prefix=/opt/sparc-elf-3.2.3 --with-gnu-as --with-gnu-ld --verbose --enable-languages=c,c++ --disable-shared --disable-nls --with-cpu=leonThread model: singlegcc version 3.2.3/cygdrive/c/SPE-C2.5/bin/../lib/gcc-lib/sparc-elf/3.2.3/cc1.exe -lang-c -v -iprefix /cygdrive/c/SPE-C2.5/bin/../lib/gcc-lib/sparc-elf/3.2.3/ -D__GNUC__=3 -D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=3 -D__GXX_ABI_VERSION= GNU CPP version 3.2.3 (cpplib) (sparc ELF)GNU C version 3.2.3 (sparc-elf)compiled by GNU C version 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125).ignoring nonexistent directory "/cygdrive/c/SPE-C2.5/sparc-elf/sys-include"ignoring nonexistent directory "/opt/sparc-elf-3.2.3/include"ignoring nonexistent directory "/opt/sparc-elf-3.2.3/lib/gcc-lib/sparc-elf/3.2.3/include"ignoring nonexistent directory "/opt/sparc-elf-3.2.3/lib/gcc-lib/sparc-elf/3.2.3/../../../../sparc-elf/sys-include"ignoring nonexistent directory "/opt/sparc-elf-3.2.3/lib/gcc-lib/sparc-elf/3.2.3/../../../../sparc-elf/include"#include "..." search starts here:#include <...> search starts here:/cygdrive/c/SPE-C2.5/lib/gcc-lib/sparc-elf/3.2.3/include/cygdrive/c/SPE-C2.5/sparc-elf/includeEnd of search list./cygdrive/c/SPE-C2.5/bin/../lib/gcc-lib/sparc-elf/3.2.3/../../../../sparc-elf/bin/as.exe --traditional-format -V -Qy -s -o ../obj/main.o /cygdrive/c/user/default/AppData/Local/Temp/ccuy9Z2h.sGNU assembler version 2.13.2.1 (sparc-elf) using BFD version 2.13.2.1View Code关于搜索路径的选项-IdirAdd the directory dir to the head of the list of directories to be searched for header files.This can be used to override a system header file, substituting your own version, since thesedirectories are searched before the system header file directories. If you use more than one`-I' option, the directories are scanned in left-to-right order; the standard systemdirectories come after.-LdirAdd directory dir to the list of directories to be searched for `-l'-Bprefix这个和-I,-L有什么关系呢?感觉有点重复。
gcc, as, ld的一些笔记
gcc, as, ld的一些笔记(一)(原创)1.本文不是教程,只是描述c语言(gcc环境),编译器,连接器,加载器,at&t汇编,ia32一些相关知识和笔记,很多需要深入的地方需要大家寻找相关的资料学习。
如果发现错误,请留言或通知我jinglexy at yahoo dot com dot cn,这个是我的msn。
打字不易,请转载时保留作者。
2.gcc安装的各个部分:g++ c++编译器,链接时使用c++库gcc c编译器,链接时使用c库cc1 实际的c编译器cc1plus 实际的c++编译器collect2 使用collect2产生特定的全局初始化代码,后台处理是传递参数给ld完成实际的链接工作。
crt0.o 初始化和结束代码libgcc 平台相关的库gcc安装需要的文件:gcc-core-3.4.6.tar.gz2 gcc核心编译器,默认只包含c编译器gcc-g++-3.4.6.tar.bz2 g++编译器gcc-testsuite-3.4.6.tar.bz2 测试套件./configure && make && make install3.binutils安装的各个部分as gnu汇编工具gprof 性能分析工具ld gnu链接器makeobjcopy 目标文件从二进制格式翻译或复制到另一种objdump 显示目标文件的各种信息strings 显示文件的字符串strip 去除符合表readelf 分析elf并显示信息链接器可以读写各种目标文件中的信息,通过BFD(binary file descriptor)提供的工具实现,BFD定义了类似a.out, elf, coff 等目标文件的格式。
4.gcc预处理程序1)define指令#可将传递的宏字符串化##将两个名字连接成一个(注意不是连接成字符串)例:#define TEST(ARGTERM) \printf(“the term “ #ARGTERM “is a string\n”) 使用__VA_ARGS__定义可变参数宏例:#define err(...) fprintf(stderr, __VA_ARGS)err (“%s %d\n”, “error code is”, 48);为了消除无参数时的逗号,可以用下面方法定义:# define err(...) fprintf(stderr, ##__VA_ARGS)一种等同的方法是:#define dprintf(fmt, arg...) printf(fmt, ##arg) 其他例:#define PASTE(a, b) a##b2)error 和 warning指令#error “y here? bad boy!”3)if, elif, else, endif指令支持的运算符:加减乘除,位移,&&,||,!等示例:#if defined (CONFIG_A) || defined (CONFIG_B)……#endif4)gcc预定义宏__BASE_FILE__ 完整的源文件名路径__cplusplus 测试c++程序__DATE____FILE__ 源文件名__func__ 替代__FUNCTION__,__FUNCTION__以被GNU不推荐使用__TIME____LINE____VERSION__ gcc版本5)几个简单例子:例1:#define min(X, Y) \(__extension__ ({typeof (X) __x = (X), __y = (Y); \(__x < __y) ? __x : __y; }))#define max(X, Y) \(__extension__ ({typeof (X) __x = (X), __y = (Y); \(__x > __y) ? __x : __y; }))这样做的目的是消除宏对X,Y的改变的影响,例如:result = min(x++, --y); printf(x, y);补充:圆括号定义的符合语句可以生成返回值,例:result = ({ int a = 5;int b;b = a + 3;}); 将返回8例2:#define dprintfbin(buf, size) do{ int i; \printf("%s(%d)@", \__FUNCTION__, __LINE__); \for(i = 0; i < size - 1; i++){ \if(0 == i % 16) \printf("\n"); \printf("0x%02x ", ((char*)buf)[i]); \} \printf("0x%02x\n", ((char*)buf)[i]); \}while(0)这个比较简单,不用解释了例3:#ifdef __cplusplusextern "C"{#endifint foo1(void);int foo2(void);#ifdef __cplusplus}#endif作用:在c++程序中使用c函数及库,c++编译程序时将函数名粉碎成自己的方式,在没有extern的情况下可能是_Z3_foo1,_Z3_foo2将导致连接错误,这里的extern表示在连接库时,使用foo1,foo2函数名。
gcc-ld 用法
gcc-ld 用法gcc-ld 是 GNU 编译器集合(GCC)中的两个重要工具,用于链接和管理库文件。
通过正确使用 gcc-ld,您可以轻松构建和运行 C、C++、Objective-C 和 Fortran 程序。
本文将详细介绍 gcc-ld 的用法,帮助您更好地掌握这两个工具的使用技巧。
一、gcc 简介gcc 是 GNU Compiler Collection 的缩写,是一个用于编译和链接多种编程语言的编译器集合。
它支持 C、C++、Objective-C、Fortran、Ada 等多种编程语言,可将源代码编译成可执行文件。
二、ld 简介ld 是 GNU Linker 的缩写,用于将多个对象文件和库文件链接成一个可执行文件或共享库。
它支持多种平台,包括 Unix、Linux、Windows 等。
使用 gcc-ld 之前,需要先安装 GCC 编译器集合。
您可以通过终端输入以下命令来安装 GCC:```shellsudo apt-get install gcc```对于 C 语言程序,可以使用以下基本命令来编译和链接:```shellgcc source.c -o executable```其中,source.c 是源代码文件,executable 是生成的可执行文件。
该命令将源代码文件编译成可执行文件,并使用 ld 链接器将链接过程自动完成。
四、深入了解 gcc-ld 的用法1. 指定库文件路径默认情况下,ld 会在系统路径中查找库文件。
如果您要链接特定的库文件,可以使用 -L 选项指定库文件路径。
例如:```shellgcc source.c -L/path/to/libs -lmylib -o executable```该命令将链接 /path/to/libs 目录下的 mylib 库文件生成可执行文件。
2. 指定库文件名称(可选)除了使用 -L 选项指定库文件路径外,还可以使用 -l 选项指定要链接的库文件名称。
lds分析
;指定输出可执行文件是elf格式,32位ARM指令,小端
OUTPUT_ARCH(arm)
;指定输出可执行文件的平台为ARM
ENTRY(_start)
_start = 0;当此段在RAM中执行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000,
即u-boot在把代码拷贝到RAM中去执行的代码段的开始) */
ldr r1, _TEXT_BASE /* 测试判断是从Flash启动,还是RAM */
现在,我们首先开看一看 xloader.lds 的代码:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(XLOADER_ENTRY) SECTIONS {
. = 0x00000000; . = ALIGN(4); .text : {
;指定输出可执行文件的起始代码段为_start.
SECTIONS
{
. = 0x00000000 . = ALIGN(4) .text :
; 从0x0位置开始 ; 代码以4字节对齐 ;指定代码段
{
cpu/arm920t/start.o (.text) ; 代码的第一个码部分 *(.text) ;其它代码部分
ld链接脚本文件解析之三
ld链接脚本文件解析之三为符号赋值.===========================你可以在一个连接脚本中为一个符号赋一个值. 这会把一个符号定义为一个全局符号.简单的赋值.------------------你可以使用所有的C赋值符号为一个符号赋值.`SYMBOL = EXPRESSION ;'`SYMBOL += EXPRESSION ;'`SYMBOL -= EXPRESSION ;'`SYMBOL *= EXPRESSION ;'`SYMBOL /= EXPRESSION ;'`SYMBOL >= EXPRESSION ;'`SYMBOL &= EXPRESSION ;'`SYMBOL |= EXPRESSION ;'第一个情况会把SYMBOL定义为值EXPRESSION. 其它情况下, SYMBOL必须是已经定义了的, 而值会作出相应的调整.特殊符号名'.'表示定位计数器. 你只可以在'SECTIONS'命令中使用它.EXPRESSION后面的分号是必须的.表达式下面会定义.你在写表达式赋值的时候,可以把它们作为单独的部分,也可以作为'SECTIONS'命令中的一个语句,或者作为'SECTIONS'命令中输出节描述的一个部分.符号所在的节会被设置成表达式所在的节.下面是一个关于在三处地方使用符号赋值的例子:floating_point = 0;SECTIONS.text :{*(.text)_etext = .;}_bdata = (. + 3) & ~ 3;.data : { *(.data) }}在这个例子中, 符号`floating_point'被定义为零. 符号'-etext'会被定义为前面一个'.text'节尾部的地址. 而符号'_bdata'会被定义为'.text'输出节后面的一个向上对齐到4字节边界的一个地址值.PROVIDE-------在某些情况下, 一个符号被引用到的时候只在连接脚本中定义,而不在任何一个被连接进来的目标文件中定义. 这种做法是比较明智的. 比如, 传统的连接器定义了一个符号'etext'. 但是, ANSI C需要用户能够把'etext'作为一个函数使用而不会产生错误. 'PROVIDE'关键字可以被用来定义一个符号, 比如'etext', 这个定义只在它被引用到的时候有效,而在它被定义的时候无效.语法是`PROVIDE(SYMBOL = EXPRESSION)'.下面是一个关于使用'PROVIDE'定义'etext'的例子:SECTIONS{.text :{*(.text)_etext = .;PROVIDE(etext = .);}在这个例子中, 如果程序定义了一个'_etext'(带有一个前导下划线), 连接器会给出一个重定义错误. 如果, 程序定义了一个'etext'(不带前导下划线), 连接器会默认使用程序中的定义. 如果程序引用了'etext'但不定义它, 连接器会使用连接脚本中的定义.。
GNU LD基本用法
GNU LD基本用法1、什么是ld?它有什么作用?ld是GNU binutils工具集中的一个,是众多Linkers(链接器)的一种。
完成的功能自然也就是链接器的基本功能:把各种目标文件和库文件链接起来,并重定向它们的数据,完成符号解析。
Linking其实主要就是完成四个方面的工作:storage allocation、symbol management、libraries、relocation。
ld可以识别一种Linker command Language表示的linker scriopt文件来显式的控制链接的过程。
通过BFD(Binary Format Description)库,ld可以读取和操作COFF(common object file format)、ELF (executable and linking format)、a.out等各种格式的目标文件。
2、常用的选项-b TARGET 设置目标文件的文件格式-e ADDRESS 设置目标文件的开始地址-EB 链接big-endian的目标文件-EL 链接small-endian的目标文件-l LIBNAME 创建执行程序时要链接的库文件(比如某个库为test,则可以为-ltest)-L DIRECTORY 寻找要链接的库文件时搜索的文件路径-o FILE 设置输出文件的名字-s 去除输出文件中的所有符号信息-S 去除输出文件中的调试符号信息-T FILE 读取链接描述脚本,以确定符号等的定位地址-v 输出ld的版本信息-x 去除所有的局部符号信息-X 去除临时的局部符号信息,默认情况下会设置这个选项-Bstatic 创建的输出文件链接静态链接库-Bdynamic 创建的输出文件链接动态链接库-Tbss ADDRESS 设置section bss的起始地址-Tdata ADDRESS 设置section data的起始地址-Ttext ADDRESS 设置section text的起始地址3、链接描述脚本链接描述脚本描述了各个输入文件的各个section如何映射到输出文件的各section中,并控制输出文件中section和符号的内存布局。
ld链接脚本文件解析之五
ld链接脚本文件解析之五展开全文输入节中的普通符号.-----------------------------------对于普通符号,需要一个特殊的标识, 因为在很多目标格式中, 普通符号没有一个特定的输入节. 连接器会把普通符号处理成好像它们在一个叫做'COMMON'的节中.你可能像使用带有其他输入节的文件名一样使用带有'COMMON'节的文件名。
你可以通过这个把来自一个特定输入文件的普通符号放入一个节中,同时把来自其它输入文件的普通符号放入另一个节中。
在大多数情况下,输入文件中的普通符号会被放到输出文件的'.bss'节中。
比如:.bss { *(.bss) *(COMMON) }有些目标文件格式具有多于一个的普通符号。
比如,MIPS ELF目标文件格式区分标准普通符号和小普通符号。
在这种情况下,连接器会为其他类型的普通符号使用一个不同的特殊节名。
在MIPS ELF的情况中,连接器为标准普通符号使用'COMMON',并且为小普通符号使用'.common'。
这就允许你把不同类型的普通符号映射到内存的不同位置。
在一些老的连接脚本上,你有时会看到'[COMMON]'。
这个符号现在已经过时了,它等效于'*(COMMON)'。
输入节和垃圾收集---------------------------------------当连接时垃圾收集正在使用中时('--gc-sections'),这在标识那些不应该被排除在外的节时非常有用。
这是通过在输入节的通配符入口外面加上'KEEP()'实现的,比如'KEEP(*(.init))'或者'KEEP(SORT(*)(.sorts))'。
输入节示例---------------------接下来的例子是一个完整的连接脚本。
lds文件浅析
ENTRY(_start) ;指定输出可执行文件的起始代码段为_start.
SECTIONS {
. = 0x00000000 ; 从0x0位置开始 . = ALIGN(4) ; 代码以4字节对齐 .text : ;指定代码段 {
cpu/arm920t/start.o (.text) ; 代码的第一个代码部分 *(.text) ;其它代码部分 } . = ALIGN(4) .rodata : { *(.rodata) } ;指定只读数据段 . = ALIGN(4);
SECTIONS { ... secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
{ contents } >region :phdr =fill ... }
secname 和 contents 是必须的,其他的都是可选的。下面挑几个常用的看看: 1、secname: 段名 2、contents:决定哪些内容放在本段,可以是整个目标文件,也可以是目标文件中的某段(代 码段、数据段等) 3、start:本段连接(运行)的地址,如果没有使用 AT(ldadr),本段存储的地址也是 start。 GNU 网站上说 start 可以用任意一种描述地址的符号来描述。 4、AT(ldadr):定义本段存储(加载)的地址。 看一个简单的例子:(摘自《2410完全开发》)
既然 程序有 了两种 地址,就涉 及到一 些跳转 指令的 区别,这里 正好写 下来 ,以后 万一忘 记了也 可 查看 ,以前 不少东 西没记 下来现 在忘得 差不多 了。。。 ARM 汇编中,常有两种跳转方法:b 跳转指令、ldr 指令向 PC 赋值。 我自 己经过 归纳如 下:
GNU-ld链接脚本浅析
输入文件: 目标文件或链接脚本文件.输出文件: 目标文件或可执行文件.目标文件(包括可执行文件)具有固定的格式, 在UNIX或GNU/Linux平台下, 一般为ELF格式. 若想了解更多, 可参考UNIX/Linux平台可执行文件格式分析有时把输入文件内的section称为输入section(input section), 把输出文件内的section称为输出section(output sectin).目标文件的每个section至少包含两个信息: 名字和大小. 大部分section还包含与它相关联的一块数据, 称为section contents(section内容). 一个section可被标记为“loadable(可加载的)”或“allocatable(可分配的)”.loadable section: 在输出文件运行时, 相应的section内容将被载入进程地址空间中.allocatable section: 内容为空的section可被标记为“可分配的”. 在输出文件运行时, 在进程地址空间中空出大小同section指定大小的部分. 某些情况下, 这块内存必须被置零.如果一个section不是“可加载的”或“可分配的”, 那么该section通常包含了调试信息. 可用objdump -h命令查看相关信息.每个“可加载的”或“可分配的”输出section通常包含两个地址: VMA(virtual memory address虚拟内存地址或程序地址空间地址)和LMA(load memory address加载内存地址或进程地址空间地址). 通常VMA和LMA是相同的.在目标文件中, loadable或allocatable的输出section有两种地址: VMA(virtual Memory Address)和LMA(Load Memory Address). VMA是执行输出文件时section所在的地址, 而LMA是加载输出文件时section所在的地址. 一般而言, 某section的VMA == LMA. 但在嵌入式系统中, 经常存在加载地址和执行地址不同的情况: 比如将输出文件加载到开发板的flash中(由LMA指定), 而在运行时将位于flash中的输出文件复制到SDRAM中(由VMA指定).可这样来理解VMA和LMA, 假设:(1) .data section对应的VMA地址是0x08050000, 该section内包含了3个32位全局变量, i、j和k, 分别为1,2,3.(2) .text section内包含由"printf( "j=%d ", j );"程序片段产生的代码.连接时指定.data section的VMA为0x08050000, 产生的printf指令是将地址为0x08050004处的4字节内容作为一个整数打印出来。
链接脚本文件(.ld.lds)详解
链接脚本⽂件(.ld.lds)详解链接脚本实例:(STM32F407VG,RT-Thread Studio⽣成的⼯程所含)* linker script for STM32F407ZG with GNU ld*//* Program Entry, set to mark it as "used"and avoid gc */MEMORY{ROM (rx) : ORIGIN = 0x08000000, LENGTH = 1024k /* 1024K flash */RAM (rw) : ORIGIN = 0x20000000, LENGTH = 128k /* 128K sram */}ENTRY(Reset_Handler)_system_stack_size = 0x400;SECTIONS{.text :{. = ALIGN(4);_stext = .;KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); *(.text) /* remaining code */ *(.text.*) /* remaining code */ *(.rodata) /* read-only data (constants) *//* section information for utest */. = ALIGN(4);__rt_utest_tc_tab_start = .;KEEP(*(UtestTcTab))__rt_utest_tc_tab_end = .;. = ALIGN(4);PROVIDE(__ctors_start__ = .);KEEP (*(SORT(.init_array.*)))KEEP (*(.init_array))PROVIDE(__ctors_end__ = .);. = ALIGN(4);_etext = .;} > ROM = 0/* .data section which is used for initialized data */.stack :{. = ALIGN(4);_sstack = .;. = . + _system_stack_size;. = ALIGN(4);_estack = .;} >RAM__bss_start = .;.bss :{. = ALIGN(4);/* This is used by the startup in order to initialize the .bss secion */_sbss = .;*(.bss)*(.bss.*)*(COMMON). = ALIGN(4);/* This is used by the startup in order to initialize the .bss secion */_ebss = . ;*(.bss.init)} > RAM__bss_end = .;_end = .;/* Stabs debugging sections. */.stab 0 : { *(.stab) }.stabstr 0 : { *(.stabstr) }.stab.excl 0 : { *(.stab.excl) }.stab.exclstr 0 : { *(.stab.exclstr) }}特别注意:1 .text section :{} .stack :{} 表⽰输出⽂件包含的 section2 {}⾥⾯的 section,是输⼊⽂件的 section,⽐如 *(.isr_vector) *(.text) *(.rodata) 这些 .isr_vector section .text section .rodata section,都有指定输⼊⽂件,*表⽰所有的输⼊⽂件;所以 *(.isr_vector) 表⽰从所有的输⼊⽂件中获取所有 .isr_vector section 放在⼀块连续的地址空间;main.o(.data) 表⽰从 main.o⽂件中获取所有的 .data section 放在⼀块连续的地址空间3 链接脚本从上往下,如果输⼊⽂件 A 已经被取出 .text section,此后输⼊⽂件 A 就没有 .text section,不能再被获取4 关于 section 的命名,名字前可以包含 .,也可以不包含,⼤多取名会包含 .。
ld中文手册完全版(带目录)
ld中文使用手册完全版(译)-1、概述 (4)2、命令行选项 (5)2.1、连接器提供大量的命令行选项, (5)2.2、连接脚本 (5)2.3、对于名称是单个字符的选项, (5)2.4、对于名称是多个字符的选项,选项前可以有一个或两个破折号; (5)2.5、多字符选项的参数 (5)2.5、注意,如果连接器通过,被编译器驱动来间接引用(比如GCC), (6)2.5.1、下面是关于被GNU连接器接受的常用命令行开关的一个列表: (6)`-aKEYWORD' (6)`-AARCHITECTURE' `--architecture=ARCHITECTURE' (6)`-b INPUT-formAT' `--format=INPUT-formAT' (6)`-d' `-dc' `-dp' (6)`-e ENTRY' `--entry=ENTRY' (6)`-E' `--export-dynamic' (7)`-EB'连接big-endian对象. 这会影响缺省输出格式 (7)`-EL'连接little-endian对象. 这会影响缺省输出格式. (7)`-g'忽略. 为了跟其它工具兼容而提供 (7)`-i'执行一个增量连接(跟'-r'等同) (7)`-init NAME' (7)`-lARCHIVE' `--library=ARCHIVE' (7)`-M' `--print-map' (7)`-n' `--nmagic', (7)`-N' `--omagic' (7)`--no-omagic' (7)`-o OUTPUT' `--output=OUTPUT' (7)`-O LEVEL' (7)`-q' `--emit-relocs' (8)`-r' `--relocateable' (8)`-R FILENAME' `--just-symbols=FILENAME' (8)`-s' `--strip-all',忽略输出文件中所有的符号信息 (8)`-S' `--strip-debug', (8)`-t' `--trace',打印ld 处理的所有输入文件的名字. (8)`-T SCRIPTFILE' `--script=SCRIPTFILE' (8)`-u SYMBOL' `--undefined=SYMBOL' (8)`-Ur' (8)`--unique[=SECTION]' (9)`-v'`--version' `-V', (9)`-x'`--discard-all'删除所有的本地符号 (9)`-X'`--discard-locals' (9)`-y SYMBOL'`--trace-symbol=SYMBOL' (9)`-Y PATH' (9)`-z KEYWORD' (9)`-( ARCHIVES -)'`--start-group ARCHIVES --end-group' (9)`--accept-unknown-input-arch'`--no-accept-unknown-input-arch' (10)`-assert KEYWORD'这个选项被忽略,只是用来跟SunOS保持兼容 (10)`-Bdynamic'`-dy'`-call_shared'连接动态链接库. (10)`-Bgroup' (10)'--no-undefined' (10)`-Bstatic'`-dn' `-non_shared' `-static' (10)`-Bsymbolic' (10)`--check-sections'`--no-check-sections' (10)`--cref' (10)`--no-define-common' (10)`--defsym SYMBOL=EXPRESSION' (10)`--demangle[=style]'`--no-demangle' (11)`--dynamic-linker FILE' (11)`--embedded-relocs' (11)`--fatal-warnings'把所有的警告视为错误 (11)`--force-exe-suffix'确保输出文件有一个.exe后缀 (11)`--no-gc-sections'`--gc-sections' (11)`--help'在标准输出上打印一个命令行选项概要,然后退出 (11)`--target-help' (11)`-Map MAPFILE' (11)`--no-keep-memory' (11)`--no-undefined'`-z defs' (11)`--allow-multiple-definition'`-z muldefs' (11)`--allow-shlib-undefined'`--no-allow-shlib-undefined' (12)`--no-undefined-version' (12)`--no-warn-mismatch' (12)`--no-whole-archive' (12)`--noinhibit-exec' (12)`-nostdlib' (12)`--oformat OUTPUT-formAT' (12)`-qmagic'这个选项被忽略,只是为了跟Linux保持兼容 (12)`-Qy'这个选项被忽略,只是为了跟SVR4保持兼容 (12)`--relax' (12)`--retain-symbols-file FILENAME' (12)'--retain-symbols-file' (13)`-rpath DIR' (13)`-rpath-link DIR' (13)`-shared'`-Bshareable' (13)`--sort-common' (13)`--split-by-file [SIZE]' (14)`--split-by-reloc [COUNT]' (14)`--stats' (14)`--traditional-format' (14)'--trafitinal-format'开关告诉ld 不要把相同的入口合并起来 (14)`--section-start SECTIONNAME=ORG' (14)`-Tbss ORG'`-Tdata ORG' `-Ttext ORG' (14)`--dll-verbose'`--verbose' (14)`--version-script=VERSION-SCRIPTFILE' (14)`--warn-common' (14)`--warn-constructors' (15)`--warn-multiple-gp' (15)`--warn-once' (15)`--warn-section-align' (15)`--whole-archive' (15)`--wrap SYMBOL' (16)`--enable-new-dtags'`--disable-new-dtags' (16)i386 PE平台的特定选项 (16)`--add-stdcall-alias' (16)`--base-file FILE' (16)`--enable-stdcall-fixup'`--disable-stdcall-fixup' (16)`--export-all-symbols' (17)3、环境变量 (17)`GNUTARGET' (17)`LDEMULATION' (17)4、连接脚本 (17)4.1、基本的连接脚本的概念 (17)4.2、连接脚本的格式 (18)4.3、简单的连接脚本示例 (18)4.4、简单的连接脚本命令. (19)4.4.1、设置入口点 (19)4.4.2、处理文件的命令. (19)`INCLUDE FILENAME' (19)`INPUT(FILE, FILE, ...)'`INPUT(FILE FILE ...)' .. (19)`GROUP(FILE, FILE, ...)'`GROUP(FILE FILE ...)'. (20)`OUTPUT(FILENAME)' (20)`SEARCH_DIR(PATH)' (20)`STARTUP(FILENAME)' (20)4.5、处理目标文件格式的命令 (20)`OUTPUT_formAT(BFDNAME)'`OUTPUT_formAT(DEFAULT, BIG, LITTLE)' (20)`TARGET(BFDNAME)' (20)4.6、其它的连接脚本命令. (21)`ASSERT(EXP, MESSAGE)' (21)`EXTERN(SYMBOL SYMBOL ...)'.. (21)`FORCE_COMMON_ALLOCATION' (21)`INHIBIT_COMMON_ALLOCATION' (21)`NOCROSSREFS(SECTION SECTION ...)' (21)`OUTPUT_ARCH(BFDARCH)' (21)4.6、为符号赋值 (21)4.7、SECTIONS命令 (22)4.7.1、输出节描述 (23)4.7.2、输出节名. (23)4.7.3、输出节描述 (23)4.7.4、输入节描述 (24)4.7.4.1、输入节通配符 (25)4.7.4.2、输入节中的普通符号. (25)4.7.4.3、输入节和垃圾收集 (26)4.7.5、输出节数据 (26)4.7.5.1、输出节关键字 (27)4.7.5.2、输出节的丢弃。
linkscript(链接器ld吃的文件)中使用宏定义的解决方案
linkscript(链接器ld吃的⽂件)中使⽤宏定义的解决⽅案问题:⼯作中遇到⼀个需求:需要在ld script中使⽤类似C语⾔的define等宏定义来做⼀些判断和替换实验:1:理论上*.c中都能⽤,是否gcc/ld也⽀持在ld script中直接⽤宏呢,结果:arm-linux-ld:xxx.lds:2: ignoring invalid character `#' in expressionarm-linux-ld:xxx.lds:2: syntax error⼈说⽔⽕⽆情,看来ld和gcc也不给⾯⼦啊。
这⾥⽤的是交叉编译的ld,x86的也是⼀样的结论,本是同根⽣嘛。
看来此路不通。
2:*.c中为什么能⽤define等宏呢,这个是在预编译阶段完成的。
我们把gcc的预编译拿来先帮我们处理⼀次是否就可以了呢?带着疑问我们继续出发先贴⼀份原始的ld script 吧:old.lds,⾥⾯有些define和注释哦1. /*2. * comments like C style3. * if comments line is less than 2 lines like this, maybe generate some strange result4. *5. */6. #ifdef __ARM__7. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")8. OUTPUT_ARCH(arm)9. #else10. OUTPUT_FORMAT("elf32-littlends", "elf32-littlends", "elf32-littlends")11. OUTPUT_ARCH(nds)12. #endif13. ENTRY(_start)14.15. SECTIONS16. {17. //C++ comments18. . = 0x00000000;19.20. . = ALIGN(__ALIGN__);21. .text : /*C style comment*/22. {23. #if defined(__ARM__)24. cpu/arm920t/start.o (.text)25. #endif26. board/xxx/lowlevel_init.o (.text)27. board/xxx/nand_read.o (.text)28. *(.text)29. }30.31. . = ALIGN(__ALIGN__);32. .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }33.34. . = ALIGN(__ALIGN__);35. .data : { *(.data) }36.37. . = ALIGN(__ALIGN__);38. __bss_start = .;39. .bss (NOLOAD) : { *(.bss) . = ALIGN(__ALIGN__); }40. _end = .;。
链接脚本文件语法详细讲解
我们对每个c或者汇编文件进行单独编译,但是不去连接,生成很多.o 的文件,这些.o文件首先是分散的,我们首先要考虑的如何组合起来;其次,这些.o文件存在相互调用的关系;再者,我们最后生成的bin文件是要在硬件中运行的,每一部分放在什么地址都要有仔细的说明。
我觉得在写makefile的时候,最为重要的就是ld的理解,下面说说我的经验:首先,要确定我们的程序用没有用到标准的c库,或者一些系统的库文件,这些一般是在操作系统之上开发要注意的问题,这里并不多说,熟悉在Linux编程的人,基本上都会用ld命令;这里,我们从头开始,直接进行汇编语言的连接。
我们写一个汇编程序,控制GPIO,从而控制外接的LED,代码如下;.text.global _start_start:LDR R0,=0x56000010 GPBCON寄存器MOV R1,# 0x00000400str R1,[R0]LDR R0,=0x56000014MOV R1,#0x00000000STR R1,[R0]MAIN_LOOP:B MAIN_LOOP代码很简单,就是一个对io口进行设置然后写数据。
我们看它是如何编译的,注意我们这里使用的不是arm-linux-gcc而是arm-elf-gcc,二者之间没有什么比较大的区别,arm-linux-gcc 可能包含更多的库文件,在命令行的编译上面是没有区别。
我们来看是如何编译的:arm-elf-gcc -g -c -o led_On.o led_On.s 首先纯编译不连接arm-elf-ld -Ttext 0x00000000 -g led_On.o -o led_on_elf用Ttext指明我们程序存储的地方,这里生成的是elf文件,还不是我们真正的bin,但是可以借助一些工具可以进行调试。
然后:arm-elf-objcopy -O binary -S led_on_elf led_on.bin生成bin文件。
GNU-LD-v2.30-中文手册
中文手册 version 2.30
2018.10.31 英文地址:https:///binutils/docs/ld/index.html
CopyCui
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU
Free Documentation License''.
目录
1 概述................................................................................................................................................. 5 2 调用................................................................................................................................................. 5 2.1 命令行选项.
GNU工具链简介
GNU工具链简介(全)2012-01-13 14:24:00分类:原文地址:GNU工具链简介(全)作者:piaoyizuMips GNU工具链简介1 . 总括本文分三部分来介绍mips的工具链,首先工具链的总括,其次是每个工具链的简介,最后是各工具链的实际应用举例。
我们的项目使用的工具链就如图1所示, 声明,本文所述的内容实乃GNU工具链的九牛之一毛, 日后会陆续更新。
图12. 工具链简介下边就以列表的方式,对每一个工具链的作用进行介绍,在下一章进行实例演示。
mips-linux-gnu-addr2line :把程序地址转换为文件名和行号。
在命令行中给它一个地址和一个可执行文件名,它就会使用这个可执行文件的调试信息指出在给出的地址上是哪个文件以及行号。
mips-linux-gnu-gcc:符合ISO标准的C编译器, 这个大家都在用,不再赘述。
mips-linux-gnu-objcopy:把一种目标文件中的内容复制到另一种类型的目标文件中。
mips-linux-gnu-ar:建立、修改、提取归档文件。
归档文件是包含多个文件内容的一个大文件,其结构保证了可以恢复原始文件内容。
mips-linux-gnu-gcov:gcov是一个保险测试工具。
当构建一个程序时,gcov会监视一个程序的执行,并且会标识出执行了哪一行源码,哪一行没有执行。
mips-linux-gnu-objdump:显示一个或者更多目标文件的信息。
使用选项来控制其显示的信息。
它所显示的信息通常只有编写编译工具的人才感兴趣。
mips-linux-gnu-as:是 GNU 汇编器,主要用来编译 GNU C 编译器 gcc 输出的汇编文件,它将汇编代码转换成二进制代码,并存放到一个object 文件中,该目标文件将由连接器 ld连接mips-linux-gnu-gdb:GNU调试器。
允许调试用C\C++和其他语言编写的应用程序。
它的基本运行方式是在shell环境下用命令方式进行调试程序和显示数据。
ld链接脚本文件解析之六
ld链接脚本文件解析之六输出节关键字-----------------------有两个关键字作为输出节命令的形式出现。
`CREATE_OBJECT_SYMBOLS'这个命令告诉连接器为每一个输入文件创建一个符号。
而符号的名字正好就是相关输入文件的名字。
而每一个符号的节就是`CREATE_OBJECT_SYMBOLS'命令出现的那个节。
这个命令一直是a.out目标文件格式特有的。
它一般不为其它的目标文件格式所使用。
`CONSTRUCTORS'当使用a.out目标文件格式进行连接的时候,连接器使用一组不常用的结构以支持C++的全局构造函数和析构函数。
当连接不支持专有节的目标文件格式时,比如ECOFF和XCOFF,连接器会自动辩识C++全局构造函数和析构函数的名字。
对于这些目标文件格式,‘CONSTRUCTORS’命令告诉连接器把构造函数信息放到‘CONSTRUCTORS’命令出现的那个输出节中。
对于其它目标文件格式,‘CONSTRUCTORS’命令被忽略。
符号`__CTOR_LIST__'标识全局构造函数的开始,而符号`__DTOR_LIST'标识结束。
这个列表的第一个WORD是入口的数量,紧跟在后面的是每一个构造函数和析构函数的地址,再然后是一个零WORD。
编译器必须安排如何实际运行代码。
对于这些目标文件格式,GNU C++通常从一个`__main'子程序中调用构造函数,而对`__main'的调用自动被插入到`main'的启动代码中。
GNU C++通常使用'atexit'运行析构函数,或者直接从函数'exit'中运行。
对于像‘COFF’或‘ELF’这样支持专有节名的目标文件格式,GNU C++通常会把全局构造函数与析构函数的地址值放到'.ctors'和'.dtors'节中。
gcc-ld 用法 -回复
gcc-ld 用法-回复GCC是GNU编译器集合中的一种常用编译器,其提供了一系列的命令行选项来编译和链接C和C++程序。
而GCC的一个重要的选项是"-ld",用于链接时指定库文件路径。
在本文中,我将详细介绍GCC的"-ld"选项的用法,以及如何一步一步使用该选项来编译和链接程序。
首先,让我们来了解一下GCC的"-ld"选项的作用和用法。
在程序的编译和链接过程中,有时需要使用一些外部库来完成特定的功能。
例如,在编写图形界面程序时,可能需要使用GTK+库;在编写网络程序时,可能需要使用sockets库。
而这些库文件通常以".so"或".a"为扩展名,并且通常保存在特定的路径下。
"-ld"选项可以告诉编译器在链接时去查找这些库文件,并将其加入到最终生成的可执行文件中。
接下来,让我们来看一个实际的案例,以进一步说明GCC的"-ld"选项的用法。
假设我们有一个简单的C程序,其中使用了数学库中的"sqrt"函数来计算一个数的平方根。
我们的任务是编译该程序,并将数学库链接到可执行文件中。
下面是程序的源代码:c#include <stdio.h>#include <math.h>int main() {double x = 16;double result = sqrt(x);printf("The square root of f is f\n", x, result);return 0;}现在,我们可以按照以下步骤来使用GCC的"-ld"选项来编译和链接这个程序:步骤1:将源码保存为一个名为"example.c"的文件。
步骤2:打开终端,并切换到保存了源码的文件夹。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
section
息.
每个“
间地址)
1,2,3.
如果
如果
如果,
赋值为
如果,
内
}
a = 3; $
$
.
输出
输出
{
...
[ ]
每个
输出
输出
输出
设置VMA
输出
例子:
和
16字节
输入
输入
.ctors section
data.o
.data section
的.text ...,最
当
当
*
?
}
data.o
的内容
都只
}
组成输出.bss section
可以用
的section
例子,
section
输入
{
all.o
}
{
}
{
}
}
输出
有
文件(非
)。
如:
错误:
正确:
FILE
输出
是出
析构。
对于
持任意
符号
符号
行)
.ctors
section
输出
例子,。
输出
{
...
TYPE 的
“不输出
例子,
{
}
输出输出
输出用法:
覆盖图...
{ {
...
...
...
...
}
那么由
对于,这...
{
}
...
}
紧跟在其后。
8.
section
...
}
NAME
ATTR
ATTR
section
R 只读
W 读/
X
A …
I
L 同I
!
例子,
{
}
section
ELF
要了解
PHDRS
}
其中
NAME
段,section
了
在TYPE
息。
TYPE
{
}
...
...
}
10.
当使用
script
0 前提
1
2
3 GNU
4
5
6
0. 前提
--
--
1.
{
} {
}
}; };
可以在如果把}; };
2.
假设};
};
$
用nm 3. GNU 文件{
} {
}
}; };
{
}
2
那么
{
}
1 $
参考:
11.
只在
{ {
} {
}
与C
优先级
(1)
VMA 例子,
{
}
在输出
在
通过
例子,
{
}。