我遇到了一个奇怪的情况,执行涉及动态链接符号的指针运算会导致不正确的结果。我不确定是否只是缺少一些链接器参数,或者它是否是链接器错误。有人可以解释以下示例中的问题吗?
考虑以下lib.c
简单共享库的代码 ( ):
#include <inttypes.h>
#include <stdio.h>
uintptr_t getmask()
{
return 0xffffffff;
}
int fn1()
{
return 42;
}
void fn2()
{
uintptr_t mask;
uintptr_t p;
mask = getmask();
p = (uintptr_t)fn1 & mask;
printf("mask: %08x\n", mask);
printf("fn1: %p\n", fn1);
printf("p: %08x\n", p);
}
fn1
有问题的操作是地址和变量之间的按位与mask
。应用程序 ( app.c
) 只是这样调用fn2
:
extern int fn2();
int main()
{
fn2();
return 0;
}
它导致以下输出...
mask: ffffffff
fn1: 0x2aab43c0
p: 000003c0
...这显然是不正确的,因为fn1
和预期的结果相同p
。代码运行在 AVR32 架构上,编译如下:
$ avr32-linux-uclibc-gcc -Os -Wextra -Wall -c -o lib.o lib.c
$ avr32-linux-uclibc-gcc -Os -Wextra -Wall -shared -o libfoo.so lib.o
$ avr32-linux-uclibc-gcc -Os -Wextra -Wall -o app app.c -L. -lfoo
编译器认为,将变量加载
mask
到 32 位寄存器 7 中并将 & 操作拆分为两个带有立即操作数的汇编操作是最佳解决方案。
$ avr32-linux-uclibc-objdump -d libfoo.so
000003ce <fn1>:
3ce: 32 ac mov r12,42
3d0: 5e fc retal r12
000003d2 <fn2>:
...
3f0: e4 17 00 00 andh r7,0x0
3f4: e0 17 03 ce andl r7,0x3ce
我假设and
指令的直接操作数没有重定位到fn1
共享库加载到应用程序地址空间时的加载地址:
- 这种行为是故意的吗?
- 如何调查链接共享库或加载可执行文件时是否出现问题?
背景:这不是一个学术问题。OpenSSL 和 LibreSSL 使用类似的代码,因此不能更改 C 源代码。该代码在其他架构上运行良好,当然有一个不明显的原因对函数指针进行按位操作。