標籤:編譯 連結
問題:工作中遇到一個需求:需要在ld script中使用類似C語言的define等宏定義來做一些判斷和替換
實驗:
1:理論上*.c中都能用,是否gcc/ld也支援在ld script中直接用宏呢,結果:
arm-linux-ld:xxx.lds:2: ignoring invalid character `#' in expressionarm-linux-ld:xxx.lds:2: syntax error
人說水火無情,看來ld和gcc也不給面子啊。這裡用的是交叉編譯的ld,x86的也是一樣的結論,本是同根生嘛。看來此路不通。
2:*.c中為什麼能用define等宏呢,這個是在先行編譯階段完成的。我們把gcc的先行編譯拿來先幫我們處理一次是否就可以了呢?帶著疑問我們繼續出發
先貼一份原始的ld script 吧:old.lds,裡面有些define和注釋哦
/* * comments like C style * if comments line is less than 2 lines like this, maybe generate some strange result * */#ifdef __ARM__OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)#elseOUTPUT_FORMAT("elf32-littlends", "elf32-littlends", "elf32-littlends")OUTPUT_ARCH(nds)#endifENTRY(_start)SECTIONS{ //C++ comments . = 0x00000000; . = ALIGN(__ALIGN__); .text : /*C style comment*/ {#if defined(__ARM__) cpu/arm920t/start.o (.text)#endif board/xxx/lowlevel_init.o (.text) board/xxx/nand_read.o (.text) *(.text) } . = ALIGN(__ALIGN__); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(__ALIGN__); .data : { *(.data) } . = ALIGN(__ALIGN__); __bss_start = .; .bss (NOLOAD) : { *(.bss) . = ALIGN(__ALIGN__); } _end = .;}
我們請gcc出馬幫忙只進行先行編譯吧:(主要是 -E 和 -P的參數,不瞭解的man gcc 或者 gcc --help)
[email protected]:~/linux_all/project$ arm-linux-gcc -E -D__ARM__ -D__ALIGN__=4 -P old.lds -o new.ldsarm-none-linux-gnueabi-gcc: old.lds: linker input file unused because linking not done
繼續被打,看了gcc還認副檔名呀。那我們忽悠忽悠它吧:
[email protected]:~/linux_all/project$ cp old.lds old.c[email protected]:~/linux_all/project$ arm-linux-gcc -E -D__ARM__ -D__ALIGN__=4 -P old.c -o new.lds
哇,居然成功糊弄過去了,趕緊看看new.lds是否是預期的呢:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{ . = 0x00000000; . = ALIGN(4); .text : { cpu/arm920t/start.o (.text) board/xxx/lowlevel_init.o (.text) board/xxx/nand_read.o (.text) *(.text) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); __bss_start = .; .bss (NOLOAD) : { *(.bss) . = ALIGN(4); } _end = .;}太cool了,gcc看來還比較好騙嘛,O(∩_∩)O哈哈~
如果客官您覺得改名成*.c感覺不是太好,那您就使用下面的一行命令來搞定它吧:(注意命令中單獨的一個"-"的用法哦)
[email protected]:~/linux_all/project$ cat old.lds | arm-linux-gcc -E -D__ARM__ -D__ALIGN__=4 -P - -o new.lds[email protected]:~/linux_all/project$ arm-linux-gcc -E -D__ARM__ -D__ALIGN__=4 -P - <old.lds -o new.lds[email protected]:~/linux_all/project$ arm-linux-gcc -E -D__ARM__ -D__ALIGN__=4 -P - <old.lds > new.lds
以上三個命令,隨便撈一個吧(一行居然沒顯示下,將就看看吧)
接下來呢,ld再吃已經處理過的new.lds就可以啦。不用我說,聰明的客官你肯定早知道了。
link script(連結器ld吃的檔案)中使用宏定義的解決方案