【问题标题】:How to link ELF32 assembly and C files?如何链接 ELF32 程序集和 C 文件?
【发布时间】:2011-04-10 14:43:36
【问题描述】:

我用 C 编写了一个简单的汇编软件 (nasm) 和一个简单的应用程序。 我的 C 代码从汇编代码中调用了一个函数,但我不知道如何编译 C 代码而不收到来自“extern int Sum();”的“未定义引用”错误行。

C 代码:

#include <stdio.h>

extern int Sum();

main()
{
  int a1, a2, x;

  x = Sum(a1, a2);
  printf("value of x is: %d\n", x);
}

汇编代码:

global _Sum

_Sum:
    push ebp
    mov  ebp, esp

    mov  eax, [ebp+8]
    mov  ecx, [ebp+12]
    add  eax, ecx
    pop  ebp
    ret

我将如何分别编译这两个文件,然后将它们链接到一个统一的文件中?

【问题讨论】:

  • 我知道这个问题很老了:但是,对于来到这里的人来说——我在下面的回答中提供的代码链接和参考书是学习汇编的好资源。希望你得到有机会去看看!

标签: c assembly compilation nasm


【解决方案1】:

您应该组装 .asm 文件以获取 .o(对象)文件,正如您所说的那样。然后你应该编译(但不是链接).c 文件以获得另一个 .o 文件,如下所示:

gcc -o whatever.o -c whatever.c

然后你应该把它们链接在一起,像这样:

gcc whatever.o asm.o

然后链接器将与所有目标代码一起运行,并且应该能够解析它需要的引用。

【讨论】:

  • 谢谢你的回答,但这只是给了我这个错误:main.o: In function main': main.c:(.text+0x1f): undefined reference to Sum' collect2: ld returned 1 exit status
  • ...当您运行第一个命令或第二个命令时?你能把你正在运行的所有命令粘贴到第一次失败吗?
  • 另外,您能否使用 objdump 或类似工具转储您的汇编代码目标文件的内容,以便我们查看其中实际包含的符号?
  • 第一次:gcc -c main.c(结果:main.o)第二次:nasm -f elf func.asm(结果:func.o)第三次:gcc main.o func.o(结果: main.o: 在函数main': main.c:(.text+0x1f): undefined reference to Sum' collect2: ld 返回 1 个退出状态)
  • objdump -t func.o:文件格式 elf32-i386 符号表:00000000 l df ABS 00000000 func.asm 00000000 l d .text 00000000 .text 00000000 g .text 00000000 _总和
【解决方案2】:

在与 ELF 一起使用的 ABI 中,C 名称不会与初始 _ 混淆。

【讨论】:

  • 修改由编译器决定,GCC 用前导下划线修改 C 函数名称
  • @Foo,GCC 做了目标 ABI 想要的,我知道没有 ABI 与 ELF 一起使用,它会用初始 _ 破坏 C 名称。如果需要,GCC 将在针对其他 ABI 时进行破坏。
【解决方案3】:

对于来这里搜索的人:查看代码并在此处预订 http://www.drpaulcarter.com/pcasm/index.php :通过 here 下载 linux 示例:您要参考的文件是 first.asm -(根据架构:下面是 32 位示例)

nasm -f elf -d ELF_TYPE asm_io.asm
nasm -f  elf32 first.asm 
gcc -o first first.o driver.c asm_io.o

【讨论】:

    【解决方案4】:

    有两种方法可以解决这个问题,将 C 源代码编译为 C(不是 C++),要将其编译为 C,您必须为其提供扩展名 .c

    第二种方式,在 C++ 代码(扩展名 .cpp)中,名称被破坏,当您编译 C++ 代码时,使用十六进制编辑器查看目标文件并搜索 Sum。在我的情况下,名称变为_Z3Sumii。如果你把汇编源代码中的名字改成这个,你会发现它可以工作。

    还要将 C++ 源代码中的extern 语句更改为以下内容,因为它需要两个int 类型的参数,例如extern int Sum(int, int);

      global _Z3Sumii
    _Z3Sumii:
      push ebp
      mov  ebp, esp
      mov  eax, [ebp+8]
      mov  ecx, [ebp+12]
      add  eax, ecx
      mov  esp, ebp
      pop  ebp
      ret
    

    编译:

    gcc -c file.cpp
    nasm -f elf32 sum.asm -o sum.o
    gcc file.o sum.o -o file
    

    【讨论】:

      【解决方案5】:

      最原生的方式是使用 GCC 工具链获取你​​的 C 程序的汇编代码,然后手动汇编这两个汇编文件并链接它们。

      【讨论】:

      • 谢谢。但是有没有办法在不使用 GCC 生成的程序集的情况下将代码链接在一起?
      • 您所说的是编译过程的两个不同阶段——汇编和链接。要手动链接文件,您可以使用标准的“ld”实用程序。
      • 我知道,但问题是当我组装 .asm 文件时。没问题。我得到一个 .o 文件。当我使用 GCC 编译 .c 文件时,它给了我一个关于未定义的“Sub”引用的错误,但我无法链接这些文件,从而在编译 .c 文件之前清除错误。这就是我的困境。
      • 由于 'Sub' 标记为外部,您需要做的就是在 GCC 工具链中限制链接器并手动链接文件。此外,GCC 中应该有一个选项可以将外部文件链接到代码。
      • 至于限制链接器,我用这个命令编译:gcc -c main.c 然后它编译得很好,然后我用这个命令组装汇编代码:nasm -f elf func。 asm,最后我像这样链接:ld main.o func.o -o program,但这给了我这个错误:ld:警告:找不到入口符号_start;默认为 0000000008048080 main.o:在函数 main': main.c:(.text+0x1f): undefined reference to Sum' main.c:(.text+0x35):未定义的对 `printf' 的引用
      【解决方案6】:

      在你的情况下:

      nasm -f elf -o sumasm.o sumasm.asm
      gcc -o sum sumasm.o sum.c 
      

      你可能需要elf32

      【讨论】:

        猜你喜欢
        • 2017-07-10
        • 2015-07-07
        • 2011-02-06
        • 1970-01-01
        • 2013-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多