2012年2月17日 星期五

XCode 編譯 i386 架構時的 "illegal text reloc to XXX" 問題

最近在協助同事編寫 Webkit Plugin。經驗上如同 iOS 實作時相仿:為了同時支援不同的架構(arm6, arm7)得將用到的 library 分別編譯出來,將利用 lipo 將它們 merge 成一個同時支援多種架構的 library,即為俗稱的 universal library。
在一開始我忘了需要不同架構的 library,因為某些 osx 需要 32bit 的 library,在我電腦上,預設編出來的是 x86_64 架構,本來以為單純編譯出 i386 的版本再合併起來就好。沒想到發生了新的問題:

ld: illegal text reloc to cstring from ../FFMPEG.i386/lib/libavformat.a(aea.o) in _aea_read_header for architecture i386
collect2: ld returned 1 exit status
Command /Developer/usr/bin/llvm-g++-4.2 failed with exit code 1


雖然不太清楚細節是什麼,總之這錯誤看起來是 linker 在進行 relocation 時發生了問題。為何這個問題只在 i386 編譯時會發生呢?剛好找到在 apple maillist 上有說明:

http://lists.apple.com/archives/unix-porting/2008/Jan/msg00027.html

*** EXPLANATION ***
The two assembly commands load the absolutes address of _trail into R15. Doing so is fine if _trail is ultimately in the same linkage unit. _trail is in libmodule.dylib.
For this to work, at runtime the dynamic loader (dyld) would have to rewrite the two instructions. Normally dyld only updates data pointers.
One work around is to make libdyalog an archive (e.g. libdyalog.a) and link that with pere.s. Then all the code would be in the same linkage unit, so there would be no need for runtime text relocs.
The runtime (dyld) does support text relocs (updating instructions) for i386, but you need to link with -read_only_relocs suppress.

相信大部分的人跟我一樣對於底層能掌握的知識不多,至少我們知道:

The runtime (dyld) does support text relocs (updating instructions) for i386, but you need to link with -read_only_relocs suppress.

索性在 other link flags 加上:

-read_only_relocs suppress

程式似乎就能正常編譯成功了。

PS. 這個 flag 不能加在 x86_64 的架構,請設定在條件式編譯選項。

沒有留言:

張貼留言