【问题标题】:ELF loading on MIPS, malloc issueMIPS 上的 ELF 加载,malloc 问题
【发布时间】:2015-08-21 21:17:03
【问题描述】:

我正在 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,我想是免费的)。所以这真的很令人费解。

【问题讨论】:

  • 你静态链接libc了吗?
  • @user35443 是的,二进制文件是静态链接的,并且 libc 也是静态链接的(加载器也有自己的 libc 副本,因为它需要做一些 mprotect/mmap 工作,但是两个副本位于不同的地址空间中)

标签: mips elf libc musl


【解决方案1】:

我不会说 MIPS 程序集,但您似乎没有设置从位于此处的 MIPS ABI 第 3-30 页开始定义的“辅助向量”:http://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - 这可能是问题的原因?

【讨论】:

  • 我在堆栈上添加了“辅助向量”,但不幸的是它似乎没有任何区别:(
【解决方案2】:

我已经有一段时间没有尝试做 MIPS 的东西了,但我认为你的辅助向量需要看起来像这样:

// main()'s pseudo arguments.
#define AT_PAGESZ 6
argv:
        .word   name
        .word   0                       // End of argv.
        .word   0                       // End of envp.
        // Auxv
        .word   AT_PAGESZ
        .word   4096                    // Page size.
        .word   0

我记得,页面大小 auxv 条目是 MIPS for musl 独有的。

【讨论】:

  • 完美运行!这正是我问这个问题时所希望的答案和专业知识,非常感谢。你拯救了我的一天。 :)
  • @Thomas 我一直致力于在裸机环境中使用 clang 和 musl。我现在正在研究 ARM,但我希望尽快回到 Mips。
  • 这很酷;到目前为止,我们将 musl 与 gcc 一起使用,musl+clang 似乎是理想的组合(gcc 相当臃肿恕我直言),但我们还没有找到时间来设置它,没有太多文档(而 @ 987654323@ 带有安装程序和预构建的 gcc 交叉编译器..)。
  • 如果您对预构建的 clang 二进制文件以及作为多个目标的库感兴趣,我可以在 ellcc.org
  • 干杯;我想这周晚些时候我会看看 ellcc.org
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 2011-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
相关资源
最近更新 更多