參考文檔:
the Gnu Linker ld
?3.5.4 Source Code Reference
Accessing a linker script defned variable from source code is not intuitive. In particular a
linker script symbol is not equivalent to a variable declaration in a high level language, it
is instead a symbol that does not have a value.
從源文件中訪問(wèn)鏈接腳本中定義的變量不能直接訪問(wèn),鏈接腳本中的變量是一個(gè)符號(hào)而不是一個(gè)具體的值
Before going further, it is important to note that compilers often transform names in the
source code into di?erent names when they are stored in the symbol table. For example,
Fortran compilers commonly prepend or append an underscore, and C++ performs extensive
‘name mangling’. Therefore there might be a discrepancy between the name of a variable
as it is used in source code and the name of the same variable as it is defned in a linker
script
For example in C a linker script variable might be referred to as:
extern int foo;
But in the linker script it might be defned as:
_foo = 1000;
however it is assumed that no name transformation has taken place.
編譯器通常會(huì)把源代碼中的name(變量名或者函數(shù)名)進(jìn)行轉(zhuǎn)換然后在存放在symbol table,例如fortran通常會(huì)在name的前或后加下劃線,因此相同的變量在源代碼中和鏈接腳本中名字可能不一樣
When a symbol is declared in a high level language such as C, two things happen. The frst is that the compiler reserves enough space in the program’s memory to hold the value of
the symbol. The second is that the compiler creates an entry in the program’s symbol table
which holds the symbol’s address. ie the symbol table contains the address of the block of memory holding the symbol’s value. So for example the following C declaration, at fle scope
int foo = 1000;
creates a entry called ‘foo’ in the symbol table. This entry holds the address of an ‘int’
sized block of memory where the number 1000 is initially stored.
在c語(yǔ)言里面聲明一個(gè)symbol,首先編譯器會(huì)保留足夠的空間去存儲(chǔ)這份symbol的值,然后會(huì)在符號(hào)表中添加一個(gè)條目來(lái)保存symbol的值,例子說(shuō)的很明確,首先symbol table中會(huì)添加一個(gè)entry,名字叫做foo,這個(gè)entry保存著foo變量的地址,地址里面存的內(nèi)容是1000
When a program references a symbol the compiler generates code that frst accesses the
symbol table to fnd the address of the symbol’s memory block and then code to read the
value from that memory block. So:
//程序引用一個(gè)symbol時(shí)首先在symbol table里面查找symbol的地址,然后在把這個(gè)地址里面的數(shù)據(jù)讀取出來(lái)
foo = 1;
looks up the symbol ‘foo’ in the symbol table, gets the address associated with this symbol
and then writes the value 1 into that address.
//這個(gè)例子說(shuō)明對(duì)變量foo的訪問(wèn)首先去 symbol table獲取foo地址,然后往改地址寫(xiě)入1
Whereas:
int * a = & foo;
looks up the symbol ‘foo’ in the symbol table, gets it address and then copies this address
into the block of memory associated with the variable ‘a(chǎn)’
//foo的地址 --->a變量
Linker scripts symbol declarations, by contrast, create an entry in the symbol table but donot assign any memory to them. Thus they are an address without a value. So for example the linker script defnition:
//鏈接腳本里聲明變量的話只會(huì)在symbol table里面添加entry,不會(huì)為其分配內(nèi)存.
foo = 1000;
creates an entry in the symbol table called ‘foo’ which holds the address of memory location
1000, but nothing special is stored at address 1000. This means that you cannot access the
value of a linker script defned symbol - it has no value - all you can do is access the address
of a linker script defned symbol.
上面的例子只是在symbol table創(chuàng)建了一個(gè)foo,地址是1000,1000為地址的內(nèi)存里面什么內(nèi)容都沒(méi)有,所以你不能訪問(wèn)foo(1000里面的內(nèi)容),你只能獲取foo的地址(1000)
Hence when you are using a linker script defned symbol in source code you should always
take the address of the symbol, and never attempt to use its value. For example suppose
you want to copy the contents of a section of memory called .ROM into a section called
.FLASH and the linker script contains these declarations:
start_of_ROM = .ROM;
end_of_ROM = .ROM + sizeof (.ROM) - 1;
start_of_FLASH = .FLASH;
Then the C source code to perform the copy would be:
extern char start_of_ROM, end_of_ROM, start_of_FLASH;
memcpy (& start_of_FLASH, & start_of_ROM, & end_of_ROM - & start_of_ROM);
Note the use of the ‘&’ operators. These are correct.
c代碼中使用變量見(jiàn)上方,需要用extern聲明.然后在取地址.
asm文件里面怎么使用呢?好像是可以直接就使用.word把__bss_start的值存在標(biāo)號(hào)_bss_start處相當(dāng)于*_bss_start = __bss_start的值
.globl _bss_start
_bss_start:
.word __bss_start
另外一個(gè)自己做實(shí)驗(yàn)的例子
Makefile
exam.bin:exam1.o
arm-linux-ld -Texam.lds -o exam1_elf $<
arm-linux-objdump -D -m arm exam1_elf > exam1_dis
%.o:%.c
arm-linux-gcc -c $<
%.o:%.S
arm-linux-gcc -c $<
clean:
rm *.o *.bin *_dis *_elf
exam.lds鏈接腳本
SECTIONS {
.text : {*.text}
__bss_start = .;
__bss_end = .;
__dd = .;
}
exam1.S文件,我直接使用lds腳本里的__dd,取其值存入r3,編譯竟然能通過(guò).也沒(méi)有報(bào)錯(cuò)說(shuō)沒(méi)有找到__dd.
.global _start
.global _bss_start
_bss_start:
.word __bss_start
.global abcd
abcd:
.word 0x1234
.global _dd
_dd:
.word __dd
_start:
mov r0, #1
nop
nop
adr r1, _bss_start
adr r2, _dd
nop
ldr r3, =__dd
查看.text段有多大,大小是0x2c,反匯編看一下最終r3寄存器是不是0x2c
book@book-desktop:~/exam/inline_asm$ objdump -h exam1_elf
exam1_elf: file format elf32-little
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000002c 00000000 00000000 00008000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .glue_7 00000000 0000002c 0000002c 0000802c 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .glue_7t 00000000 0000002c 0000002c 0000802c 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
3 .data 00000000 0000002c 0000002c 0000802c 2**0
CONTENTS, ALLOC, LOAD, DATA
4 .bss 00000000 0000002c 0000002c 0000802c 2**0
ALLOC
exam1_dis反匯編文件
24: e51f3004 ldr r3, [pc, #-4] ; 28
r3確實(shí)是0x2c
exam1_elf: file format elf32-littlearm
Disassembly of section .text:
00000000 <_bss_start>:
0: 0000002c andeq r0, r0, ip, lsr #32
00000004 <abcd>:
4: 00001234 andeq r1, r0, r4, lsr r2
00000008 <_dd>:
8: 0000002c andeq r0, r0, ip, lsr #32
0000000c <_start>:
c: e3a00001 mov r0, #1 ; 0x1
10: e1a00000 nop (mov r0,r0)
14: e1a00000 nop (mov r0,r0)
18: e24f1020 sub r1, pc, #32 ; 0x20
1c: e24f201c sub r2, pc, #28 ; 0x1c
20: e1a00000 nop (mov r0,r0)
24: e51f3004 ldr r3, [pc, #-4] ; 28 <.text+0x28>
28: 0000002c andeq r0, r0, ip, lsr #32
把反匯編的代碼拿到keil里去仿真,結(jié)果與上面分析的一致
