我有一個複雜的構建過程中一個很大的軟件項目,其工作原理是這樣:MIPS,ELF和部分連接
- 編譯單獨的源文件。
- 使用
ld -r
將每個模塊的目標文件部分鏈接到另一個.o。 - 使用
objcopy -G
隱藏每個模塊中的私有符號。 - 部分鏈接模塊對象,再次使用
ld -r
。 - 將模塊鏈接到共享對象中。
需要執行步驟3以允許未導出到項目其餘部分的模塊專用全局變量。
這一切都適用於ARM和IA32。不幸的是,現在我不得不在mips上工作(特別是Android的mipsel-linux-gnu)。 MIPS共享對象ABI比其他平臺複雜得多,並且它不工作。
發生了什麼事是第5步中得到這個錯誤:
CALL16 reloc at 0x1234 not against global symbol
這似乎是因爲編譯器生成CALL16搬遷調用函數在另一個編譯單元,但CALL16只允許你叫全局符號---因爲第3步,我們試圖調用的一些符號不再是全球性的。
在這一點上我可以看到幾個可能的選項:
- 說服連接在步驟2
- 同上化解CALL16搬遷到正常的內部編譯單元相對於PC的通話,但在步驟4或5.
- 告訴編譯器不要爲編譯單元函數調用生成CALL16重定位。
- 其他。
由於外部要求,禁用步驟3恐怕不是選項。
我真的很想做的就是生成絕對代碼,在加載時將代碼打到正確的地址;它更小,更快,並且更簡單,我們不需要在進程之間共享庫。不幸的是,似乎Android的dlopen()
似乎不支持這一點。
目前我超出了我的深度。任何人有任何建議?
這是gcc 4.4.5(來自Emdebian),binutils 2.20.1。目標BFD是elf32-tradlittlemips。主機操作系統是Linux,我正在爲Android進行交叉編譯。
附錄
我也得到這樣的警告,從第4步。
$MODULE.o: Can't find matching LO16 reloc against `$SYMBOLNAME' for R_MIPS_GOT16 at 0x18 in section `.text.$SYMBOLNAME'
望着輸入的拆卸步驟4,我可以看到,編譯器生成這樣的代碼:
50: 8f9e0000 lw s8,0(gp)
50: R_MIPS_GOT16 $SYMBOLNAME
54: 8fd9001c lw t9,28(s8)
58: 0320f809 jalr t9
5c: 00a02021 move a0,a1
不GOT16修復了高半地址,並且應該跟隨低LO16的LO16?但代碼看起來像它試圖做一個GOT間接尋址。這讓我感到困惑。我不知道這是否與我先前的問題,或者是一個不同的問題,或者是不是在所有問題......
更新
顯然MIPS根本不支持隱藏全球符號!
我們已經通過改變應該隱藏的符號的名稱來繞過它,以便沒有人知道它們是什麼。這大大推動了外部需求,但是我通過指出這是獲得可運送產品的唯一方式,從而將管理層賣給了它。
這是完全可怕的(並且涉及到一些深惡心的makefile工作要做),所以我寧願像一個更好的解決辦法,如果任何人有一個...