--- title: 連結器和執行檔資料 tags: C 語言筆記 --- ## 連結器和執行檔資料 ### 嵌入一個二進位檔案到執行檔 * 範例一 * 利用 ```$uname -a > blob``` 來產生一個 text 檔案 * 然後可以先 ```$uname -a | wc -c ``` 看一下檔案大小 * 之後再利用 ```$ld -s -r -b binary -o blob.o blob ``` 把 blob 轉成 binary file blob.o 輸出 * 可以用 ```$objdump -t blob.o``` 觀察輸出 ``` blob.o: file format elf64-x86-64 SYMBOL TABLE: 0000000000000000 l d .data 0000000000000000 .data 0000000000000070 g .data 0000000000000000 _binary_blob_end 0000000000000000 g .data 0000000000000000 _binary_blob_start 0000000000000070 g *ABS* 0000000000000000 _binary_blob_size ``` * 然後用一個測試檔案 test.c,其中 extern 代表這個參數不是在這個 .c 檔裡面宣告的 ```c= #include <stdio.h> int main(void) { extern void *_binary_blob_start, *_binary_blob_end; void *start = &_binary_blob_start, *end = &_binary_blob_end; printf("Data: %p..%p (%zu bytes)\n", start, end, end - start); return 0; } ``` * 進行編譯 ```$gcc test.c blob.o -o test```,後執行可得 ```Data: 0x559914241010..0x559914241080 (112 bytes)``` * 也可以用 ```$strings test``` 來看 _binary_blob_end、_binary_blob_end 有沒有在裡面 ### ld script 基本術語 * linker: 將多個 input files 輸出為一個 output file,每個檔案則稱做 object file (目的檔),輸出檔則常稱做 executable (可執行檔),當然也能稱為 object file * Symbols: 將名稱對應到一個記憶體位址的 symbol 稱為 defined symbol,名稱沒有對應到記憶體位址的稱為 undefined symbol,例如 int a ,a 就是一個 defined symbol。 * Symbol Visibility: Symbols 通常透過 static and extern 來調整作用範圍,因此分成全域變數、靜態變數或是函數的名稱。一般來說,如果把單獨的c編譯成object file時: * defined symbol 為該檔案內的 global variable, static varible 和funciton * undefined symbol 為該檔案內的 extern variable 和外部 funciton * Section: * section包含: * section 的名稱 * section 的內容 * section 的大小 * 狀態可以分為 LOADABLE 和 ALLOCATABLE: * LOADABLE: 執行時該 section 是否需要被載入到記憶體 * ALLOCATABLE: 先保留記憶體的一塊空間讓程式執行時使用,如.bss * 非 LOADABLE 或是 ALLOCATABLE 的 section,通常是裝載著 debugging information * Section 記憶體位址: Output section 如果被載入記憶體,會存放兩種記憶體位址 * VMA (Virtual Memory Address): 當 output file 運作時,section 會得到這個 address。放在 RAM * LMA (Load Memory Address): 當 section 被載入 (loaded) 時,會放置到這個 address。放在 ROM/Flash * 通常時候 VMA = LMA * 可以使用objdump -h看VMA/LMA資訊 * Linker script 範例 * .text 放程式碼、.data 放初始化變數、.bss 放未初始化全域變數 ```c= SECTIONS { . = 0x10000; .text : { *(.text) } . = 0x8000000; .data : { *(.data) } .bss : { *(.bss) } } ``` * ```.``` 表示 location counter * 第三行先將 location counter 移到 0x10000 * 第四行 把 所有 輸入 object 檔案 的程式機械碼中 ({ *(.text) }) 存放到 輸出object檔案 的 .text 區塊中 * 後面就以此類推 * 常用的功能 * ENTRY: 在 linker script 中可以指定 entry point,也就是程式執行時第一個執行的指令開始位置,ex: ```ENTRY(_start)``` * MEMORY: Linker 預設會取用全部的記憶體,我們可以用 MEMORY 指令指定記憶體大小,ORIGIN 代表起始位置,LENGTH 為長度 ```c= MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 128K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K } ``` * KEEP: 當有開啟 link-time garbage collection 的時候,有時候我們希望某個區段不要被回收掉,這時候就可以使用 KEEP,使用方式為將 input section wildcard entry 放入 KEEP 中,ex: ```KEEP(*(.init))``` * 接下來SECTION部分,就能用 > 符號把資料寫到指定的位置 ```c= SECTIONS { .text : { KEEP(*(.isr_vector)) *(.text) } >FLASH } ``` [10分鐘讀懂-linker-scripts](https://blog.louie.lu/2016/11/06/10%E5%88%86%E9%90%98%E8%AE%80%E6%87%82-linker-scripts/) [Linker Script初探](http://wen00072.github.io/blog/2014/03/14/study-on-the-linker-script/#assign) [linker-script-簡單教學](https://evshary.com/2018/06/02/linker-script-%E7%B0%A1%E5%96%AE%E6%95%99%E5%AD%B8/) [GNU ld的linker script簡介](https://www.slideshare.net/zzz00072/gnu-ldlinker-script)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up