我正在 MIPS(32 位)中加载一个普通的静态链接 ELF 二进制文件。在映射可加载段之后,这是我在跳转到目标 ELF 的 CRT_start
函数之前设置堆栈的方式:
__asm__(" \
addi $2, %[envN], 0 ;\
.env_loop: \
addi $2, $2, -4 ;\
lw $3, 0($2) ;\
addi $sp, $sp, -4 ;\
sw $3, 0($sp) ;\
bne $2, %[env0], .env_loop ;\
addi $2, %[argN], 0 ;\
.arg_loop: \
addi $2, $2, -4 ;\
lw $3, 0($2) ;\
addi $sp, $sp, -4 ;\
sw $3, 0($sp) ;\
bne $2, %[arg0], .arg_loop ;\
addi $2, %[argc], 0 ;\
addi $sp, $sp, -4 ;\
sw $2, 0($sp) ;\
addi $2, %[func], 0 ;\
jr $2 ;"
:
: [envN] "r" (envp + envc + 1),
[env0] "r" (envp),
[argN] "r" (argv + argc + 1),
[arg0] "r" (argv),
[argc] "r" ((int32_t)argc),
[func] "r" (entry_point)
: "$2", "$3", "cc", "memory"
);
所以我将环境变量、命令行参数推argc
送到堆栈上,最后跳到目标 ELF 的入口点。这工作正常,我最终在加载程序的主函数中使用正确的命令行参数和所有内容,除了一件事:malloc
不起作用!对它的任何调用都返回 null 并将 errno 设置为ENOMEM
。
我正在使用的 MIPS 模拟器(qemu-system-mips)有足够的可用内存,如果我只是启动程序而不使用我的加载器,它工作正常,所以它必须来自加载器。但我不知道为什么;我对 x86、x86_64 和 arm 使用了相同的加载技术,它们都工作得很好,但是由于某种原因 malloc 在加载器的 MIPS 版本中出现故障。
我在这里错过了什么吗?在跳转到加载的可执行文件之前实际上需要完成的事情,这可能对 MIPS 很重要,但对我成功尝试过的其他架构不重要?我想我会在这里问是否有人遇到过这个问题,因为我真的无法想象这里出了什么问题。
我在 Linux 下运行它并使用 musl 作为 libc。经过一些调试后,我发现 musl 的expand_heap
函数存在差异,但我还没有汇编信息的来源,所以不清楚错误是什么(musl 对其他架构使用相同的 malloc 代码,它们工作得很好) .
二进制文件是静态链接的(包括 libc;它没有动态依赖项),其他所有内容(printf、fopen 等)在加载的二进制文件中都可以正常工作,但 malloc 显然是唯一的例外(当然还有 realloc/calloc 和我想是免费的)。所以这真的很令人费解。