在.so中混合使用c/c++和assembly时避免文本重定位

avoiding text relocations when mixing c/c++ and assembly in a .so

本文关键字:assembly 文本 定位 c++ 混合 so      更新时间:2023-10-16

我正在尝试从.中删除所有文本重定位,以便混合c、c++和汇编。对于c/c++,fpic负责PIC。

在Android ARM目标上,我们能够从c/c++调用导出的asm函数,而不会导致文本重新定位。但在我们的实现中,我们有数据数组,这些数组必须可以从C++和汇编访问。在C++上,它是一个普通的旧数组,即extern "C" { __declspec(align(32)) int16_t myarray[256]; },而在asm端,我们使用.global myarray

第二次我们在asm端使用这样的符号时,我们会在final.so中看到文本重定位,这可以通过scanelfreadelf看到。api模式23下的安卓L加载程序将完全拒绝加载这样的.so.

问题:-这个问题是意料之中的事吗?-是否在C或asm端使用一些特殊声明来确保没有文本重定位?

编辑:一个最小的例子有用吗?

感谢所有的评论。因此,为了其他所有与安卓M作战的人的利益,我们能够解决我们的一些问题。我现在的理解如下,如果我错了,请纠正我:

1) 我无法在asm中直接指向外部全局变量(即ldr)而不引起文本重定位。

2) 即使不是全局的,我也无法在asm中引用数据节中包含的符号,因为在汇编时,从文本到数据的相对地址是未知的。为什么.so链接器不能在链接时解决这个问题我不确定,但我只能假设相对地址太远,或者根据PIC的性质,数据/文本的相对地址在运行时是未知的(?)。

所以我们的解决方案是:

1) 预生成数组并添加到文本部分,尽可能靠近使用它的代码(相对指令的距离有限)。我们发现,将表放在离使用它的代码太远的地方失败了。

2) 从标签加载时,首选使用"adr"而不是"ldr",因为这似乎可以确保您从当前部分加载,并帮助我们避免一些文本重定位

幸运的是,我们的数组是静态数据,尽管是在运行时生成的,并且可以在汇编时转换为常量。但是,对于那些数组或内存是动态的,必须从C传递到asm的情况,我看不出有其他选择可以将其作为参数传递给汇编代码,正如一些人在评论中所建议的那样。

一个有用的解读是:ARM-将地址加载到寄存器

您可以尝试下面的代码,它对我有效

//==============================================

文件:asm.s

.globl asm_test
.LglobalInt:
    .int    globalInt-.
asm_test:
    push {LR}
    // change the value of globalInt variable
    LDR r1, .LglobalInt
    adr r2, .LglobalInt
    add r0, r1, r2
    ldr r1, =123456789
    STR r1, [r0]
    pop {LR}
    bx lr

//==============================================

文件:test.c

int globalInt = 0;
int main()
{
    printf("globalInt = %dn", globalInt);
    asm_test();
    printf("globalInt = %dn", globalInt);
}