最近有位同事遇到個問題,他們的模塊提供給產品的共享庫是帶有.text.rel段的,而android N的linker限制共享庫不能有TEXTREL,導致加載失敗。
首先,該模塊有大量的彙編代碼,即使有編譯開關-fPIC,生成的so仍然帶有TEXTREL。
其次,linker對so的這個限制只針對API level大於22,本來只需要修改AndroidManifest.xml中的target sdk version就可以解決,但是產品端比較強勢,改不了。
沒有辦法了,只能針對.text.rel中所有重定位符號,一個個修正,好在不多。
但是遇到了個問題,有一個重定位符號,是一個段名,源碼大概如此:
.section .rodata
.align 4
pmovmskb_byte:
.byte 1,2,4,8,16,32,64,128
.byte 1,2,4,8,16,32,64,128
...
.text
...
movrel r1, pmovmskb_byte
...
movrel是自定義宏,定義爲:
.macro movrel rd, val
ldr \rd, =\val
.endm
最終利用了開源代碼,將movrel修改爲相對pc尋址來解決了。
至於原因,在arm官網貌似找到了答案:
https://community.arm.com/tools/f/discussions/532/problem-in-generating-position-independent-code-with-out-textrel
1. 當告訴armasm彙編器,增加pic開關‘--apcs /fpic',合理的情況下,RO sections會標記爲PIC,這和C/C++編譯器不同,增加'--apcs /fpic'會告訴編譯器,必須把RO sections目標代碼標記爲PIC。彙編器不能增加相對PC來尋址的relocation,但編譯器可以。
所以,如果是C/C++與arm指令混合編碼,arm指令是否爲PIC不受c/c++編譯開關-fPIC的影響。
2. 彙編代碼中使用了DCD or LDR rx,=等指令,會造成絕對尋址,彙編代碼無法再被優化,只能在運行時重定位,所以增加了TEXTREL