版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
楼主 |
发表于 2016-12-6 16:30
|
显示全部楼层
Linux链接脚本学习--lds
, p) g; D' P3 @4 \/ |. ] F) E
5 H% Q/ n$ P. o% N9 F1 `& X# e6 t( {8 ^% P& H
一、概论
; l& {, W) p. k% l' |" e" T/ Q+ u: C$ R: @* S* g) f
ld:+ @% A/ o6 R. H6 ~& l
! Z2 r- G4 h- L9 U9 ]: RGNU的链接器.
) \7 N' D/ L: y6 Z, I$ M1 Q" ?# ^) R9 D
用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用.
8 O) A) X! R+ \% M% \% q0 @' C/ J; s( s, L1 @+ G
一般编译一个程序时,最后一步就是运行ld进行链接
: Z* o8 D i6 ^/ w7 @' D1 G( p* Q: r3 H" h- O' @. h. ? o
每一个链接都被一个链接脚本所控制,这个脚本是用链接命令语言书写的.) j, u$ Y4 h. r. n& r$ Q5 t
+ a9 N. `5 Y) E% C* S5 o# X二、链接脚本
p' ?0 R% l, I; y$ Y
% W' F2 X+ {) h4 a) f/ J) ^链接脚本的一个主要目的是描述输入文件中的各个段(数据段,代码段,堆,栈,bss)如何被映射到输出文件中,并控制输出文件的内存排布.0 J4 X N# S; n! E5 d. O% P0 B
: P. M& U1 w( `
链接器总是使用链接脚本的,如果你不提供,则链接器会使用一个缺省的脚本,这个脚本是被编译进链接器可执行文件的.
7 @! b6 p; ?* d l, g2 q) t* a% O6 ]5 i* c6 t+ L) ?) v+ H
可以使用--verbose命令行显示缺省的链接器脚本的内容.9 X+ d6 u4 Q& p5 t p& V1 q
8 Z5 S, W- n! L* u" k: s P
你可以使用-T命令行来提供你自己的链接脚本来替换缺省的链接脚本.
0 g/ L* }) n/ E* i
9 V/ H$ c, j' \9 `# o/ B三、简单的链接脚本示例.
+ X- a: Z' h$ a8 L& x! r! _7 D* B( |8 ^# C- O! k2 N
许多脚本是相当简单的.' J. Y3 Y+ L+ k1 t; ^
6 c" S4 C# x6 j" [7 r. ^1 F M
可能最简单的脚本只含有一个命令:’SECTIONS’.. V- A4 E& H/ u, \' ~4 Q' q
* d! _# C/ E5 {8 ?) F6 ~% i你可以使用’SECTIONS’来描述输出文件的内存布局.6 j ~2 c, e& d, `1 D/ P3 e$ ^- s
$ g" \( @1 l3 d. i8 q& U- {+ Y‘SECTIONS’是一个功能很强大的命令.
8 F+ {2 m1 g+ T8 E: W6 r
1 p( i# r* D1 B ]9 _# l( A假设你的程序只有代码段,初始化过的数据段,和未初始化过的数据段.这些会存在于’.text’,’data’,’bss’段中.+ P4 w$ }, |& I( x4 I( f1 n
% n5 q6 T! }) a( X/ m, o0 @对于这个例子,假设代码应该被载入到地址0x1000处,而数据应该从0x8000000开始,如下是实现这个功能的脚本:
# f Z7 q: P/ e) d( K& k! P2 E
: N8 h& F$ E" t/ cSECTIONS3 K' } _! `1 K- F2 D
5 i/ I4 v) }" v$ `" r) E( j' o{4 X6 [/ Z" C+ D, r& P# ^$ d
4 ?; Q o: v/ l1 H4 k. ^.=0x1000;
6 {, J& b; i* k3 h+ o6 X; w4 c& S
.text:{*(.text)}9 s9 M. w9 j- H/ ]% d
- e) I5 J. q0 [( v2 }
.=0x8000000;
" @0 ]. X* G6 G2 @: X+ i* U* Y( y! @
( U: a8 ?, B4 t5 t.data:{*(.data)}
4 y! ~' U6 }- |% E; A
4 N- |/ m, }: v6 D7 i- X1 W.bss:{*(.bss)}
+ G5 h/ k: ]3 |- M8 b/ J) ^9 B/ B' I. Y# V5 g+ H
}; v! T! N& \6 z+ m# s" A% C5 V$ a
/ R/ j2 f: g) j$ a2 ?' }
具体分析:% T3 o8 x, d. F8 P
( { s. @) x* G2 B
关键字’SECTIONS’开始于这个配置.后面跟有一串放在花括号中的符号赋值和输出端描述的内容.1 I6 v9 M# { H
/ Z/ d' \) o& ^; M) \4 ]
第一行是对一个特殊的符号’.’赋值,这是一个定位标识器.如果你没有以其他的方式制定输出段的地址,那地址值就会被设为定位标识器的现有值,即0x1000.9 j# J1 A9 F5 l% u
/ ~1 a1 L$ A0 @& t, `
第二行定义一个输出段,’.text’.冒号’:’是语法需要,现在可以被忽略.段后面的花括号中,应该列出所有应该放入这个输出段中的输入端的名字.’*’是通配符,匹配所有文件名.即将所有输入文件中的.text段都保存在此段中.
( n+ V0 q3 O' Y* d5 v- J
# F- l3 @% _: F1 z, k9 `余下的是.data和.bss段,同理,链接器会把所有.data段从地址0x8000000开始处放置.8 n4 E, n/ E3 v( s7 x
& O6 k" c' w" g; [ f5 j0 \
最后,定位标识器的值变为0x8000000加上所有.data段的地址.此时链接器把所有.bss放在此处开始的地址./ t* r$ B5 K& D5 @; E3 }4 |
- @# g0 Q- G0 }: @
) F, l$ c3 w* {, }- d
8 S8 H. h9 ~, C* a% I, }% l四、简单的链接脚本命令
& Q. W2 }3 a7 r. g: [. Q
/ b/ E" K3 X* b- B' q设置入口点
1 ^! ?, z/ l- b) |0 r0 D1 j) W+ |9 N8 Y; C! c- V+ z
在运行一个程序时,第一个被执行到的指令成为”入口点”.你可以使用”ENTRY”链接脚本命令来设置入口点.参数是一个符号名,如下: I8 \. E, ?, E+ B, `* N' v m8 u
. m$ A" x( h) y3 D
ENTRY(SYMBOL)- j& p4 M2 Q" F" D- e1 E
3 d5 w# l1 _) }$ u* o有很多不同的方法来设置入口点.链接器会通过按顺序尝试一下方法来设置入口点,如果成功了,就会停止.2 W- }' P0 b' \ [
4 Z) X; x# Z2 f! r" t; t {
1,’-e’ 入口命令行选项0 B& c/ W" X$ e3 H* f, a9 S
3 A! d' I# A6 R1 {1 \, ?2,链接脚本中的ENTRY(SYMBOL)命令
- A1 n7 Z9 w4 B2 ^; c* W0 x+ l
3,如果定义了start,就使用start的值; r% f ]6 ~. n n
& z( z6 |) r; D; l5 }- U4 D) {
4,如果存在就使用’.text’段的首地址% I, U, p/ I8 Z
% o- _+ s$ ?! {0 B! H3 e. ?% C/ L5,地址’0’; S- r! L/ b' R. Q. h
& g% U n" G( ^4 u
# V% F# j8 h8 \ r# A! T
- v4 J9 d4 j) h: a* c1 g2 A$ r
' n2 D5 v, N& Y+ s: t
& W0 Q; ~! m( I8 r) L2 x ( y# r. y6 ?: _
1 {7 P% H' {& z; h1 K, ~- @: \0 A五、命令行设置链接地址4 C( s/ a( y3 b y0 V. [0 h
0 ^, u8 p0 O9 b. t9 r
ld用于将多个obj或者so(库)文件链接成可执行文件.
$ o2 v7 j* T% o1 p0 n5 t( }; n
5 _$ [9 ~+ s! `: Y; n使用-T选项可以指定数据段,代码段,bss段起始位置.(-T只用于链接bootloader、内核等没有底层软件支持的软件.链接运行于操作系统之上的应用程序时,一般使用默认方式链接).
* H1 Y6 O/ e( o% y! f. {! t2 E3 |) W* p# \( M P
1,直接指定代码段、数据段、bss段起始地址
4 T* q# U$ |1 S8 G) N$ g) Y" q& W2 {! ^4 @ O0 K
如下:
& M6 ], V) h' `7 Z _+ [3 [ A
% R6 z7 i v* u/ p-Ttext startaddr
6 U8 x0 l: k0 x, e' E
6 v* \/ Q5 ?' a C \-Tdata startaddr
/ C6 a$ ]" t3 G5 G
7 A6 w8 A r3 m-Tbss startaddr
0 t$ ?* D6 v1 S
5 t$ m8 I' p) G, r3 C! @4 Y& v4 C例如:- r1 o5 ]' W' }% N% }6 G+ U
( Q8 j3 U( m+ R2 K- _& sld –Ttext 0x00000000 –g led_on.o –o led_on_elf) l/ F; a: z" O$ _
5 E- y) D% ?" C8 ~2,直接使用链接脚本来设置起始地址3 O0 J1 O* ?1 [/ r
t5 ^: M& }/ G$ W4 k
ld –Ttimer.lds –o timer_elf a.o b.o
! x6 u5 I8 \8 B! k
: W' e: g- I p: L" Z, ~8 o链接脚本timer.lds内容如下:
1 \) E% K9 b7 \8 u
& N$ m) K- [1 H" P) |! |SECTIONS{
( C8 k1 a- H- _ ]( d1 Q- V* {- Y. x3 |9 v
.=0x30000000;5 ~& c5 F% I3 t" ]8 N4 |+ m2 ]! I
6 ?7 O- M$ {1 X: x4 {/ Y- [- T8 R, c
.text : {*(.text)}! @1 ~ l; A% w( ~; W7 ~
* ~ o: @% }( i7 F1 j
.rodata ALIGN(4) : {*(.rodata)}
5 h# p9 o! u' q2 L9 w. e9 j x4 j' t' Y! _/ M" Z4 [2 D
.data ALIGN(4) : {*(.data)}8 M" j% t6 M, U2 n; R; T# n' q
' }$ u8 H/ c; k$ s8 ?% t.bss ALIGN(4) : {*.(.bss) *(COMMON)}# |) N3 f* s* j& Y, b/ k
7 G8 e) f0 A& q
}: @* G( @+ [5 T+ {6 [9 a- l
0 M7 D$ Q( v! y3 h% G- G7 N一个SECTIONS命令内部包含一个或多个段,段(section)是连接脚本的基本单元,它表示输入文件中的某部分怎么放置.' k) `5 i+ L! ?. O
|
|