2011-11-11 68 views
4

我有一個複雜的構建過程中一個很大的軟件項目,其工作原理是這樣:MIPS,ELF和部分連接

  1. 編譯單獨的源文件。
  2. 使用ld -r將每個模塊的目標文件部分鏈接到另一個.o。
  3. 使用objcopy -G隱藏每個模塊中的私有符號。
  4. 部分鏈接模塊對象,再次使用ld -r
  5. 將模塊鏈接到共享對象中。

需要執行步驟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工作要做),所以我寧願像一個更好的解決辦法,如果任何人有一個...

回答

1

我不知道有關特定GOT您遇到的問題。在binutils中有很多bug和GOT,LO16/HI16等問題。我認爲大多數已被修正在你使用的版本中,除非你的目標是MIPS16(你似乎沒有這樣做)。因爲你有32位寄存器,所以LO16實際上只在那裏需要,除了MIPS16之外,你將GOT的全部26位偏移量拉出。 LO16不是必需的,但仍然是一些ABI/API正式要求的,但它最多隻能是一個警告(如果您正在使用它,您可以嘗試刪除該階段的錯誤)。我只是老老實實地理解那部分的基礎知識,其餘的情況我都有一些建議,如果不是答案(很難確定你的設置是否複雜)。在MIPS(以及我熟悉的大多數程序集)中,您具有基本的三個可見性級別:本地,全局和弱點。另外你還有通訊共享對象。當然,GNU喜歡讓事情更復雜,並增加更多。天然氣提供受保護的,隱藏的和內部的(最低限度,很難跟上所有的擴展)。通過所有這些步驟,手動擺弄可見性的設置看起來沒有必要。

如果您可以刪除變量的中間全局性,則應刪除您需要使其成爲全局變量,這隻能用於簡化稍後遇到的任何GOT問題。

整體問題有點混亂。我不確定隱藏的全局符號是什麼意思,這有點矛盾(當然,可移植性和特定項目會帶來瘋狂的問題和限制)。你似乎想要在一個階段交叉裝配單元符號,但不是在以後的階段。如果不使用GNU擴展(在我的書中最好避免的),你可能需要用comm和/或weakglobals替換步驟1-2中的全局變量。你總是可以使用使用預處理器欺騙來避免在舞臺上有多個子單元(醜陋,但這是這個級別的可移植代碼)。

你真的有一個設置1)子模塊2)子模塊 - >模塊3-5)模塊 - >共享庫。簡化不能傷害。您可以始終在2)或3-5)處插入一個C級接口,以查找GCC將爲您的架構生成的裝配,並將其用作打開清晰接口的基礎。

希望我可以給你一個量身定製的解決方案,但如果沒有你的完整項目,這是不可能的。我可以放心的是,雖然MIPS的位置(特別是工具鏈)有問題,但可見性選項(特別是在使用gas,libbfd和gcc時)是相同的。

0

你的binutils太舊了。 2.23中的一些變更集可能會解決您的問題,如「隱藏沒有PLT或GOT引用的符號」。