我正在尝试在 Gem 5 模拟器中运行一小段 hello-world MIPS 程序。该程序使用 gcc 4.9.2 和 glibc 2.19(由 crosstool-ng 构建)编译,在 qemu 中运行良好,但在 gem5 中因页面错误(试图访问地址 0)而崩溃。
代码相当简单:
#include <stdio.h>
int main()
{
printf("hello, world\n");
return 0;
}
file ./test
结果:
./test:ELF 32 位 LSB 可执行文件,MIPS,MIPS-I 版本 1,静态链接,用于 GNU/Linux 3.15.4,未剥离
在使用 gdb 进行一些调试后,我发现页面错误是由_dl_setup_stack_chk_guard
glibc 中的函数触发的。它接受一个调用函数_dl_random
传递的 void 指针__libc_start_main
,它恰好是NULL
. 但是,据我所知,这些函数从不取消引用指针,而是生成指令以从内存_dl_random
指针指向的加载值。一些代码片段可能有助于理解:
在函数中(未设置__libc_start_main
宏):THREAD_SET_STACK_GUARD
/* Initialize the thread library at least a bit since the libgcc
functions are using thread functions if these are available and
we need to setup errno. */
__pthread_initialize_minimal ();
/* Set up the stack checker's canary. */
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
# ifdef THREAD_SET_STACK_GUARD
THREAD_SET_STACK_GUARD (stack_chk_guard);
# else
__stack_chk_guard = stack_chk_guard;
# endif
在函数中_dl_setup_stack_chk_guard
(总是内联):
static inline uintptr_t __attribute__ ((always_inline))
_dl_setup_stack_chk_guard (void *dl_random)
{
union
{
uintptr_t num;
unsigned char bytes[sizeof (uintptr_t)];
} ret = { 0 };
if (dl_random == NULL)
{
ret.bytes[sizeof (ret) - 1] = 255;
ret.bytes[sizeof (ret) - 2] = '\n';
}
else
{
memcpy (ret.bytes, dl_random, sizeof (ret));
#if BYTE_ORDER == LITTLE_ENDIAN
ret.num &= ~(uintptr_t) 0xff;
#elif BYTE_ORDER == BIG_ENDIAN
ret.num &= ~((uintptr_t) 0xff << (8 * (sizeof (ret) - 1)));
#else
# error "BYTE_ORDER unknown"
#endif
}
return ret.num;
}
反汇编代码:
0x00400ea4 <+228>: jal 0x4014b4 <__pthread_initialize_minimal>
0x00400ea8 <+232>: nop
0x00400eac <+236>: lui v0,0x4a
0x00400eb0 <+240>: lw v0,6232(v0)
0x00400eb4 <+244>: li a0,-256
0x00400eb8 <+248>: lwl v1,3(v0)
0x00400ebc <+252>: lwr v1,0(v0)
0x00400ec0 <+256>: addiu v0,v0,4
0x00400ec4 <+260>: and v1,v1,a0
0x00400ec8 <+264>: lui a0,0x4a
0x00400ecc <+268>: sw v1,6228(a0)
0x4a1858 (0x4a0000 + 6232)
是地址_dl_random
0x4a1854 (0x4a0000 + 6228)
是地址__stack_chk_guard
页面错误发生在0x00400eb8
。我不太明白指令是如何生成的0x00400eb8
。0x00400ebc
有人可以解释一下吗?谢谢。