2011-02-23 18 views
3

我正在構建一個在裸機上具有可重定位代碼的項目。它是一個Cortex M3嵌入式應用程序。我沒有動態鏈接器,並在我的啓動代碼中實現了所有重定位。帶有可重定位代碼的靜態局部變量的問題

大多數情況下它正在工作,但我的本地靜態變量似乎位置不正確。他們的地址被我的可執行文件在內存中的偏移量所抵消 - 也就是說,我編譯我的代碼,就好像它在內存位置0加載一樣,但實際上我將它加載到位於0x8000的內存中。靜態局部變量的內存地址偏移0x8000,這是不好的。

我的全局變量由GOT正確定位,但靜態局部變量根本不在GOT中(至少在運行readelf -r時它們不會出現)。我使用-fpic編譯我的代碼,鏈接器指定了-fpic-pie。我想我必須缺少編譯和/或鏈接選項,以指示gcc將GOT用於靜態局部變量,或指示它使用絕對尋址。

看來,目前代碼將PC添加到靜態局部變量的位置。

回答

3

我想我已經重複你所看到的:

 
statloc.c 

unsigned int glob; 

unsigned int fun (unsigned int a) 
{ 
    static unsigned int loc; 

    if(a==0) loc=7; 
    return(a+glob+loc); 
} 

 
arm-none-linux-gnueabi-gcc -mcpu=cortex-m3 -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -fpic -pie -S statloc.c 

其中給出:

.cpu cortex-m3 
    .fpu softvfp 
    .thumb 
    .text 
    .align 2 
    .global fun 
    .thumb 
    .thumb_func 
fun: 
    ldr r3, .L6 
.LPIC2: 
    add r3, pc 
    cbnz r0, .L5 
    ldr r1, .L6+4 
    movs r2, #7 
.LPIC1: 
    add r1, pc 
    ldr ip, .L6+8 
    str r2, [r1, #0] 
    ldr r1, [r3, ip] 
    ldr r3, [r1, #0] 
    adds r0, r0, r3 
    adds r0, r0, r2 
    bx lr 
.L5: 
    ldr ip, .L6+8 
    ldr r2, .L6+12 
    ldr r1, [r3, ip] 
.LPIC0: 
    add r2, pc 
    ldr r2, [r2] 
    ldr r3, [r1, #0] 
    adds r0, r0, r3 
    adds r0, r0, r2 
    bx lr 
.L7: 
    .align 2 
.L6: 
    .word _GLOBAL_OFFSET_TABLE_-(.LPIC2+4) 
    .word .LANCHOR0-(.LPIC1+4) 
    .word glob(GOT) 
    .word .LANCHOR0-(.LPIC0+4) 
    .size fun, .-fun 
    .comm glob,4,4 
    .bss 
    .align 2 
.LANCHOR0 = . + 0 
    .type loc.823, %object 
    .size loc.823, 4 
loc.823: 
    .space 4 

我還添加了啓動代碼和編譯的二進制和拆卸,以進一步瞭解/驗證到底是怎麼回事。

 
this is the offset from the pc to the .got 
    ldr r3, .L6 
add pc so r3 holds a position independent offset to the .got 
    add r3, pc 
offset in the got for the address of the glob 
    ldr ip, .L6+8 
read the absolute address for the global variable from the got 
    ldr r1, [r3, ip] 
finally read the global variable into r3 
    ldr r3, [r1, #0] 


this is the offset from the pc to the static local in .bss 
    ldr r2, .L6+12 
add pc so that r2 holds a position independent offset to the static local 
in .bss  
    add r2, pc 
read the static local in .bss  
    ldr r2, [r2] 

所以,如果你要改變這裏的.text被加載並進行了更改其中兩個的.got和.bss相對於加載與.text區段,就是這樣,然後的.got的內容是錯誤的,全局變量會從錯誤的地方加載。

如果您要更改.text加載的位置,請將.bss留在鏈接器放置的位置,並將.got相對於.text移動。那麼全局將被從正確的地方拉出來,並且本地不會

如果要更改.text的加載位置,請更改.got和.bss相對於.text加載的位置並將.got內容修改爲反映加載了.text的位置,然後從正確的位置訪問本地變量和全局變量。

所以loader和gcc/ld都需要同步。我的直接建議是不使用靜態本地,只使用全局。或者不用擔心位置獨立的代碼,畢竟它是一個cortex-m3並且資源有限,只是先定義內存映射。我假設的問題是,如何讓gcc使用.got作爲本地全局,並且我不知道答案,但是採用上面這樣的簡單示例,您可以使用許多命令行選項,直到找到一個改變輸出。

+0

不幸的是這個應用程序,我需要得到位置獨立工作。很高興看到您能夠重現我目前發現的內容。以下工作: – Dan 2011-02-24 01:33:03

+0

在鏈接器腳本中將GOT設置爲在SRAM中。在flash中保留.dynamic,以便可以找到符號表。使用符號表查找文本,數據,編輯等。從閃存複製GOT並修改內容? – Dan 2011-02-24 01:40:09

+0

正如我在這裏所做的那樣,我會採取一個簡單的例子,就像上面創建一個超級簡單的啓動文件一樣,只需一個_Start:和bl樂趣,並使用各種鏈接器腳本構建,以確切查看工具鏈的功能。就我個人而言,我採用KISS方法,並且所有內容都位於不可重定位的.text段中,而.bss init並不重要,因爲在我第一次寫之前我從未閱讀過。基本上我不是一個gnu鏈接器專業人員,也許有人在聽誰可能知道如何操作這些段而不必在加載器中解決它。 – 2011-02-24 02:24:07