鏈接腳本文件中定義的符號(hào)怎么在c源文件,匯編.s文件中引用

參考文檔:
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é)果與上面分析的一致

keil仿真結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容