2016-11-09 153 views
0

我有對imx6q鏈接代碼(皮質-A9)鏈接腳本:巨大的二進制文件的大小,而LD鏈接

OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 
OUTPUT_ARCH(arm) 
ENTRY(Reset_Handler) 
/* SEARCH_DIR(.) */ 
GROUP(libgcc.a libc.a) 
/* INPUT (crtbegin.o crti.o crtend.o crtn.o) */ 

MEMORY { 
/* IROM (rwx) : ORIGIN = 0x00000000, LENGTH = 96K */ 
    IRAM (rwx) : ORIGIN = 0x00900000, LENGTH = 256K 
    IRAM_MMU (rwx): ORIGIN = 0x00938000, LENGTH = 24K 
    IRAM_FREE(rwx): ORIGIN = 0x00907000, LENGTH = 196K 
    DDR (rwx) : ORIGIN = 0x10000000, LENGTH = 1024M 
} 

/* PROVIDE(__cs3_heap_start = _end); */ 

SECTIONS { 
    .vector (ORIGIN(IRAM) + LENGTH(IRAM) - 144):ALIGN (32) { 
    __ram_vectors_start = . ; 
    . += 72 ; 
    __ram_vectors_end = . ; 
    . = ALIGN (4); 
    } >IRAM 

    . = ORIGIN(DDR); 
    .text(.) :ALIGN(8) { 
     *(.entry) 
     *(.text) 
     /* __init_array_start = .; */ 
     /* __init_array_end = .; */ 
     . = ALIGN (4); 
     __text_end__ = .; 
    } >DDR 

    .data :ALIGN(8) { 
     *(.data .data.*) 
     __data_end__ = .; 
    } 

    .bss(__data_end__) : { 
     . = ALIGN (4); 
     __bss_start__ = .; 
     *(.shbss) 
     *(.bss .bss.* .gnu.linkonce.b.*) 
     *(COMMON) 
     __bss_end__ = .; 
    } 

    /*  . += 10K; */ 
    /*  . += 5K; */ 

    top_of_stacks = .; 
    . = ALIGN (4); 
    . += 8; 
    free_memory_start = .; 

    .mmu_page_table : { 
    __mmu_page_table_base__ = .; 
    . = ALIGN (16K); 
    . += 16K; 
    } >IRAM_MMU 

    _end = .; 
    __end = _end; 
    PROVIDE(end = .); 
} 

當我建的二進制文件的大小隻有6 KB。但我不能添加任何初始化變量。當我添加一個初始化變量時,二進制大小跳轉到〜246 MB。這是爲什麼?我試圖通過指定確切的位置並在數據段中提供> DDR來嘗試在文本部分的位置處鏈接數據段。儘管這似乎將二進制大小減少到6 KB,但二進制文件無法啓動。我怎麼能保持我的代碼在DDR和數據,BSS,堆棧和堆內部RAM本身,輕二進制大小?

我在另一個線程讀取,「在鏈接腳本使用內存標籤應該解決的內存浪費的問題」,這可怎麼辦呢?

linker script wastes my memory

普萊舍辦問別人需要什麼。我對連接腳本沒有任何經驗。請幫助

給定如下:沒有初始化的二進制數據的readelf --sections輸出,

There are 19 section headers, starting at offset 0xd804: 

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .vector   NOBITS   0093ff80 007f80 000048 00 WA 0 0 32 
    [ 2] .text    PROGBITS  10000000 008000 0016fc 00 AX 0 0 8 
    [ 3] .text.vectors  PROGBITS  100016fc 0096fc 000048 00 AX 0 0 4 
    [ 4] .text.proc  PROGBITS  10001744 009744 000034 00 AX 0 0 4 
    [ 5] .bss    NOBITS   0093ffc8 007fc8 000294 00 WA 0 0 4 
    [ 6] .mmu_page_table NOBITS   00938000 008000 004000 00 WA 0 0 1 
    [ 7] .comment   PROGBITS  00000000 009778 00001f 01 MS 0 0 1 
    [ 8] .ARM.attributes ARM_ATTRIBUTES 00000000 009797 00003d 00  0 0 1 
    [ 9] .debug_aranges PROGBITS  00000000 0097d8 000108 00  0 0 8 
    [10] .debug_info  PROGBITS  00000000 0098e0 0018a7 00  0 0 1 
    [11] .debug_abbrev  PROGBITS  00000000 00b187 00056f 00  0 0 1 
    [12] .debug_line  PROGBITS  00000000 00b6f6 00080e 00  0 0 1 
    [13] .debug_frame  PROGBITS  00000000 00bf04 000430 00  0 0 4 
    [14] .debug_str  PROGBITS  00000000 00c334 0013dd 01 MS 0 0 1 
    [15] .debug_ranges  PROGBITS  00000000 00d718 000020 00  0 0 8 
    [16] .shstrtab   STRTAB   00000000 00d738 0000cb 00  0 0 1 
    [17] .symtab   SYMTAB   00000000 00dafc 000740 10  18 60 4 
    [18] .strtab   STRTAB   00000000 00e23c 000511 00  0 0 1 
Key to Flags: 
    W (write), A (alloc), X (execute), M (merge), S (strings) 
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) 
    O (extra OS processing required) o (OS specific), p (processor specific) 

,並給出初始化的數據是二進制的readelf --sections輸出,

There are 20 section headers, starting at offset 0xd82c: 

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .vector   NOBITS   0093ff80 007f80 000048 00 WA 0 0 32 
    [ 2] .text    PROGBITS  10000000 008000 0016fc 00 AX 0 0 8 
    [ 3] .text.vectors  PROGBITS  100016fc 0096fc 000048 00 AX 0 0 4 
    [ 4] .text.proc  PROGBITS  10001744 009744 000034 00 AX 0 0 4 
    [ 5] .data    PROGBITS  0093ffc8 007fc8 000004 00 WA 0 0 8 
    [ 6] .bss    NOBITS   0093ffcc 007fcc 000294 00 WA 0 0 4 
    [ 7] .mmu_page_table NOBITS   00938000 008000 004000 00 WA 0 0 1 
    [ 8] .comment   PROGBITS  00000000 009778 00001f 01 MS 0 0 1 
    [ 9] .ARM.attributes ARM_ATTRIBUTES 00000000 009797 00003d 00  0 0 1 
    [10] .debug_aranges PROGBITS  00000000 0097d8 000108 00  0 0 8 
    [11] .debug_info  PROGBITS  00000000 0098e0 0018b6 00  0 0 1 
    [12] .debug_abbrev  PROGBITS  00000000 00b196 000580 00  0 0 1 
    [13] .debug_line  PROGBITS  00000000 00b716 00080e 00  0 0 1 
    [14] .debug_frame  PROGBITS  00000000 00bf24 000430 00  0 0 4 
    [15] .debug_str  PROGBITS  00000000 00c354 0013dd 01 MS 0 0 1 
    [16] .debug_ranges  PROGBITS  00000000 00d738 000020 00  0 0 8 
    [17] .shstrtab   STRTAB   00000000 00d758 0000d1 00  0 0 1 
    [18] .symtab   SYMTAB   00000000 00db4c 000770 10  19 62 4 
    [19] .strtab   STRTAB   00000000 00e2bc 000513 00  0 0 1 
Key to Flags: 
    W (write), A (alloc), X (execute), M (merge), S (strings) 
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) 
    O (extra OS processing required) o (OS specific), p (processor specific) 

希望這就夠了...!

注意:我正在使用arm-none-eabi-gcc進行鏈接。

+0

你可以發佈'readelf --sections'的輸出給你的二進制文件嗎? –

+0

輸出已添加。在第二種情況下,二進制文件的大小在前一個文件中被編譯爲6 KB時變成了〜246MB .... – Ajeesh

+1

很明顯(和類似的問題(或Q/A)在SO上)。 'IRAM LENGTH = 256K'帶有DDR(256MB) - IRAM(9MB)〜= 256MB',二進制增加到246MB。 [閱讀關於VMA/LMA](https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html)並將其用作搜索術語。A ** BINARY **必須是一個連續的二進制塊!沒有部分信息。你看到這個問題嗎? gnu LD腳本有'AT'類型的指令,LMA/VMA可以解決這個問題。 –

回答

1

如果您對鏈接器腳本沒有經驗,那麼可以使用一個剛剛工作的腳本,或者製作或借用更簡單的腳本。這是一個簡單的例子,這應該證明最有可能發生的事情。

MEMORY 
{ 
    bob : ORIGIN = 0x00001000, LENGTH = 0x100 
    ted : ORIGIN = 0x00002000, LENGTH = 0x100 
    alice : ORIGIN = 0x00003000, LENGTH = 0x100 
} 

SECTIONS 
{ 
    .text : { *(.text*) } > bob 
    .data : { *(.text*) } > ted 
    .bss : { *(.text*) } > alice 
} 

第一個程序

.text 
.globl _start 
_start: 
mov r0,r1 
mov r1,r2 
b . 

並不意味着只是創造了一個細分一些字節一個真正的程序就是一切。

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .text    PROGBITS  00001000 001000 00000c 00 AX 0 0 4 

12字節的.text這是地址爲0x1000在內存中,這正是我們告訴它做的事。

如果我使用-objcopy a.elf -O binary a.bin,我得到一個12字節的文件,「binary」文件格式是一個內存映像,從地址中有一些內容的第一個地址開始空間並以地址空間中最後一個字節的內容結尾。因此,而不是0x1000 + 12個字節二進制是12個字節廣告用戶必須知道它需要加載在0x1000。

所以改變這種了一點:

.text 
.globl _start 
_start: 
mov r0,r1 
mov r1,r2 
b . 
.data 
some_data: .word 0x12345678 

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .text    PROGBITS  00001000 001000 00000c 00 AX 0 0 4 
    [ 2] .data    PROGBITS  00002000 002000 000004 00 WA 0 0 1 

現在我們必須在0x1000的12個字節,在爲0x2000 4個字節,所以-O二進制必須給我們一個內存映像從第一個規定的字節到最後所以這將是0x1000 + 4。

足夠肯定4100字節,正是它所做的。

.text 
.globl _start 
_start: 
mov r0,r1 
mov r1,r2 
b . 
.data 
some_data: .word 0x12345678 
.bss 
some_more_data: .word 0 

這給

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .text    PROGBITS  00001000 001000 00000c 00 AX 0 0 4 
    [ 2] .data    PROGBITS  00002000 002000 000004 00 WA 0 0 1 
    [ 3] .bss    NOBITS   00003000 003000 000004 00 WA 0 0 1 

現在我只拿到了一個4100字節的文件,實際上並不奇怪,假定自舉是要零級的.bss這樣didnt成長「二進制「文件。

有一個親密的關係。系統級設計。鏈接器腳本和引導程序之間。對於你正在嘗試做的事情(只是ram no rom),你可能會用一個簡單得多的鏈接器腳本來獲得,與我一樣,但如果你關心.bss被調零,那麼你可以使用一些技巧用途:

MEMORY 
{ 
    ram : ORIGIN = 0x00001000, LENGTH = 0x3000 
} 
SECTIONS 
{ 
    .text : { *(.text*) } > ram 
    .bss : { *(.text*) } > ram 
    .data : { *(.text*) } > ram 
} 

確保至少有一個。數據項和你的「二進制」將與BSS已經歸零完整的圖像,引導只需要設置堆棧指針(S)並跳轉到主(如果這是C)。

無論如何,希望你能看到從12字節跳轉到4100字節是因爲增加了一個.data元素和「二進制」格式不得不填充「二進制」文件,以便該文件是一個內存圖像從數據的最低地址到數據的最高地址(在這種情況下,從0x1000到0x2000 + sizeof(.data)-1)。更改鏈接器腳本,0x1000和0x2000,這一切都改變了。將他們的.text置換爲0x2000,.data置換爲0x1000,現在「binary」文件必須是0x2000-0x1000 + sizeof(.text)而不是0x2000-0x1000 + sizeof(.data)。或0x100C字節而不是0x1004。回到第一個鏈接描述文件並在0x20000000處創建.data現在「二進制」將是0x20000000-0x1000 + sizeof(.data),因爲這是需要多少信息才能在單個文件中生成內存映像。

這很可能是正在發生的事情。如此處所示,通過簡單地添加一個數據字,文件大小從12個字節變爲4100個。

編輯。

那麼,如果你空載的數據,那麼你的初始化的變量不會被初始化,就是這麼簡單

unsigned int類型X = 5;

如果您放棄(NOLOAD).data將不會是5。

如上所述並且再次聲明,您可以將數據放入.text扇區,然後使用更多鏈接器腳本foo來讓引導程序找到該數據。

MEMORY { 鮑勃:ORIGIN = 0x00001000,LENGTH = 0x100的 泰德:ORIGIN = 0x00002000,LENGTH = 0x100的 愛麗絲:ORIGIN = 0x00003000,LENGTH = 0x100的 } SECTIONS { 的.text:{(的.text)}>鮑勃 。數據:{(的.text)}>泰德AT>鮑勃 的.bss:{(的.text)}>愛麗絲>鮑勃 }

這將創建一個16字節的「二進制」文件。 12個字節的指令和4個字節的.data。但是你不知道數據在哪裏,除非你做了一些硬編碼,這是一個壞主意。這是在您的鏈接描述文件中找到的東西,如bss_startbss_end

像這樣

MEMORY 
    { 
     bob : ORIGIN = 0x00001000, LENGTH = 0x100 
     ted : ORIGIN = 0x00002000, LENGTH = 0x100 
     alice : ORIGIN = 0x00003000, LENGTH = 0x100 
    } 
    SECTIONS 
    { 
     .text : { *(.text*) } > bob 
     .data : { 
      __data_start__ = .; 
      *(.data*) 
     } > ted AT > bob 
     __data_end__ = .; 
     __data_size__ = __data_end__ - __data_start__; 
     .bss : { *(.text*) } > alice AT > bob 
    } 

    .text 
    .globl _start 
    _start: 
    mov r0,r1 
    mov r1,r2 
    b . 


hello: 
    .word __data_start__ 
    .word __data_end__ 
    .word __data_size__ 

    .data 
    some_data: .word 0x12345678 

這給了我們。

Disassembly of section .text: 

00001000 <_start>: 
    1000: e1a00001 mov r0, r1 
    1004: e1a01002 mov r1, r2 
    1008: eafffffe b 1008 <_start+0x8> 

0000100c <hello>: 
    100c: 00002000 andeq r2, r0, r0 
    1010: 00002004 andeq r2, r0, r4 
    1014: 00000004 andeq r0, r0, r4 

Disassembly of section .data: 

00002000 <__data_start__>: 
    2000: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000 

和工具鏈/鏈接器創建和鏈接腳本填充這些定義的名稱,然後將它們填充到你的代碼時,它解決了那些外觀等。然後你的引導程序需要使用這些變量(以及更多,我沒有包括在哪裏在.text中找到。數據在上面你知道,有4個字節,他們需要登陸在0x2000但在0x1000。文本區域是那4個字節找到了嗎?更多鏈接腳本foo。還要注意gnu鏈接器腳本對於定義這些變量的位置非常敏感,在波形括號之前或之後可以有不同的結果

這就是爲什麼我提到它如果這是一個基於ROM的目標,並且你想要.data和清零.bss,那麼你幾乎必須將.data和.bss的大小和位置放在flash/ROM區域中,並且bootstrap具有複製並歸零;或者,您可以選擇不使用.data或.bss

unsigned int x=5; 
unsigned int y; 

代替

unsigned int x; 
unsigned int y; 
... 
x=5; 
y=0; 

是的,它是不是有效的二進制大小明智的,但連接器腳本都非常的工具鏈依賴性,隨着時間的推移GNU例如鏈接腳本的langauge /規則的改變,是什麼在之前的工作gnu ld的主要版本不一定適用於當前版本或下一版本,因此多年來我不得不重新構建我的最小鏈接器腳本。

如此處所示,您可以使用命令行工具來試驗設置和位置,並查看工具鏈生成的內容。

底線聽起來像你在.data中添加了一些信息,但然後說明你想要NOLOAD它,基本上這意味着.data沒有/使用你的變量沒有正確初始化,所以爲什麼麻煩改變代碼導致這一切發生只是讓它無法正常工作?要麼有.data並正確使用它,要有正確的引導程序和鏈接器腳本對,要麼只是將RAM打包到相同的RAM空間中,或者不要使用您使用的「二進制」格式,請使用elf或ihex或srec或其他。

取決於你的系統的另一個訣竅是構建RAM的二進制文件,所有打包的,然後有另一個程序,圍繞該二進制從ROM運行並複製到RAM和跳轉。以上面的16字節程序爲例,編寫另一個包含那個16字節的文件,並將它們複製到0x1000,然後分支到0x1000。根據系統和閃存/ ROM技術和接口,無論如何你都希望這樣做,我日常工作中的系統使用spi閃存來啓動,這已知有讀取干擾問題,並且... spi ..所以最快,最乾淨,最可靠的解決方案就是在做任何事情之前做好複製跳轉。使鏈接器腳本作爲免費副作用變得更容易。

+0

問題似乎當我添加(NOLOAD)到數據部分時會消失。無論如何要確定? – Ajeesh

+1

'NOLOAD'意味着數據部分不是二進制文件的一部分。你必須做的事情(如果你沒有隻有BSS或零初始化內存)將初始數據值放在主映像中,並將引導代碼複製到最終位置。 (LMA加載存儲器地址和VMA虛擬存儲器地址,它是所有彙編器應參考的實際最終絕對地址), –