【问题标题】:Linking an assembler program: error "undefined reference to `printf'"链接汇编程序:错误“未定义对‘printf’的引用”
【发布时间】:2016-03-26 06:47:02
【问题描述】:

我正在尝试在 x64 Debian 上编译 x86 assembly code

BITS 32

%include    'training.s' 

global main
extern  exit    

; ===============================================
section .text

main:
    ; The program begins here:

    call    read_hex    
    mov     edx,eax
    call    read_hex    
    add     eax,edx
    add     eax,eax
    inc     eax         

    call    print_eax   

    ; Exit the process:
    push    0
    call    exit

我收到以下错误:

~$nasm -f elf -g 0_strange_calc.asm && ld -o 0_strange_calc 0_strange_calc.o
    ld: i386 architecture of input file `0_strange_calc.o' is incompatible with i386:x86-64 output
    ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
    0_strange_calc.o:training.s:25: undefined reference to `printf'
    0_strange_calc.o:training.s:35: undefined reference to `printf'
    0_strange_calc.o:training.s:45: undefined reference to `printf'
    0_strange_calc.o:training.s:56: undefined reference to `read'
    0_strange_calc.o:training.s:77: undefined reference to `scanf'
    0_strange_calc.o:training.s:97: undefined reference to `scanf'
    0_strange_calc.o:training.s:108: undefined reference to `printf'
    0_strange_calc.o:training.s:129: undefined reference to `printf'
    0_strange_calc.o:training.s:137: undefined reference to `printf'
    0_strange_calc.o:0_strange_calc.asm:50: undefined reference to `exit'




 ~$ yasm -f elf64 0_strange_calc.asm
    ~$ gcc -m32 -nostdlib -nostdinc 0_strange_calc.o -o 0_strange_calc
    /usr/bin/ld: i386:x86-64 architecture of input file `0_strange_calc.o' is incompatible with i386 output
    /usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 00000000080480c0
    0_strange_calc.o: In function `no symbol':
    0_strange_calc.asm:(.text+0x8): undefined reference to `printf'
    0_strange_calc.asm:(.text+0x19): undefined reference to `printf'
    0_strange_calc.asm:(.text+0x2a): undefined reference to `printf'
    0_strange_calc.asm:(.text+0x39): undefined reference to `read'
    0_strange_calc.asm:(.text+0x5b): undefined reference to `scanf'
    0_strange_calc.asm:(.text+0x7a): undefined reference to `scanf'
    0_strange_calc.asm:(.text+0x89): undefined reference to `printf'
    0_strange_calc.asm:(.text+0xa8): undefined reference to `printf'
    0_strange_calc.asm:(.text+0xb9): undefined reference to `printf'
    0_strange_calc.o: In function `main':
    0_strange_calc.asm:(.text+0xdb): undefined reference to `exit'
    collect2: error: ld returned 1 exit status

这是我的 0_strange_calc.o 转储:

~$ objdump -M intel -d 0_strange_calc.o

0_strange_calc.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main-0xc2>:
   0:   60                      (bad)  
   1:   50                      push   rax
   2:   68 00 00 00 00          push   0x0
   7:   e8 00 00 00 00          call   c <main-0xb6>
   c:   83 c4 08                add    esp,0x8
   f:   61                      (bad)  
  10:   c3                      ret    
  11:   60                      (bad)  
  12:   50                      push   rax
  13:   68 00 00 00 00          push   0x0
  18:   e8 00 00 00 00          call   1d <main-0xa5>
  1d:   83 c4 08                add    esp,0x8
  20:   61                      (bad)  
  21:   c3                      ret    
  22:   60                      (bad)  
  23:   b8 00 00 00 00          mov    eax,0x0
  28:   50                      push   rax
  29:   e8 00 00 00 00          call   2e <main-0x94>
  2e:   83 c4 04                add    esp,0x4
  31:   61                      (bad)  
  32:   c3                      ret    
  33:   60                      (bad)  
  34:   51                      push   rcx
  35:   57                      push   rdi
  36:   6a 00                   push   0x0
  38:   e8 00 00 00 00          call   3d <main-0x85>
  3d:   83 c4 0c                add    esp,0xc
  40:   31 d2                   xor    edx,edx
  42:   c6 04 07 00             mov    BYTE PTR [rdi+rax*1],0x0
  46:   61                      (bad)  
  47:   c3                      ret    
  48:   55                      push   rbp
  49:   89 e5                   mov    ebp,esp
  4b:   83 ec 04                sub    esp,0x4
  4e:   53                      push   rbx
  4f:   51                      push   rcx
  50:   52                      push   rdx
  51:   8d 5d fc                lea    ebx,[rbp-0x4]
  54:   53                      push   rbx
  55:   68 00 00 00 00          push   0x0
  5a:   e8 00 00 00 00          call   5f <main-0x63>
  5f:   83 c4 08                add    esp,0x8
  62:   8b 03                   mov    eax,DWORD PTR [rbx]
  64:   5a                      pop    rdx
  65:   59                      pop    rcx
  66:   5b                      pop    rbx
  67:   c9                      leave  
  68:   c3                      ret    
  69:   55                      push   rbp
  6a:   89 e5                   mov    ebp,esp
  6c:   83 ec 04                sub    esp,0x4
  6f:   8d 5d fc                lea    ebx,[rbp-0x4]
  72:   60                      (bad)  
  73:   53                      push   rbx
  74:   68 00 00 00 00          push   0x0
  79:   e8 00 00 00 00          call   7e <main-0x44>
  7e:   83 c4 08                add    esp,0x8
  81:   61                      (bad)  
  82:   8b 03                   mov    eax,DWORD PTR [rbx]
  84:   c9                      leave  
  85:   c3                      ret    
  86:   60                      (bad)  
  87:   56                      push   rsi
  88:   e8 00 00 00 00          call   8d <main-0x35>
  8d:   83 c4 04                add    esp,0x4
  90:   61                      (bad)  
  91:   c3                      ret    
  92:   60                      (bad)  
  93:   b9 20 00 00 00          mov    ecx,0x20
  98:   d1 c0                   rol    eax,1
  9a:   89 c2                   mov    edx,eax
  9c:   83 e2 01                and    edx,0x1
  9f:   51                      push   rcx
  a0:   50                      push   rax
  a1:   52                      push   rdx
  a2:   68 00 00 00 00          push   0x0
  a7:   e8 00 00 00 00          call   ac <main-0x16>
  ac:   83 c4 08                add    esp,0x8
  af:   58                      pop    rax
  b0:   59                      pop    rcx
  b1:   e2 e5                   loop   98 <main-0x2a>
  b3:   68 00 00 00 00          push   0x0
  b8:   e8 00 00 00 00          call   bd <main-0x5>
  bd:   83 c4 04                add    esp,0x4
  c0:   61                      (bad)  
  c1:   c3                      ret    

00000000000000c2 <main>:
  c2:   e8 81 ff ff ff          call   48 <main-0x7a>
  c7:   89 c2                   mov    edx,eax
  c9:   e8 7a ff ff ff          call   48 <main-0x7a>
  ce:   01 d0                   add    eax,edx
  d0:   01 c0                   add    eax,eax
  d2:   40 e8 28 ff ff ff       rex call 0 <main-0xc2>
  d8:   6a 00                   push   0x0
  da:   e8 00 00 00 00          call   df <main+0x1d>

好像已经在x64 asm中转换成功了,其他简单的代码我编译链接都没有问题。我究竟做错了什么?我该如何解决?

【问题讨论】:

  • 我认为错误信息很清楚:i386 architecture is incompatible with i386:x86-64.
  • 它看起来也希望你的入口点被命名为“start”而不是“main”

标签: assembly x86 nasm 32-bit debian-based


【解决方案1】:

你有几个选择

  • 使用 LD 链接到最终的可执行文件
  • 使用 GCC 链接到最终的可执行文件

使用 LD 方法

您的命令行使用LD,不幸的是这会带来很多问题。第一个:

ld: 输入文件 `0_strange_calc.o' 的 i386 架构与 i386:x86-6 不兼容

您在 64 位 Debian 上,试图生成 32 位可执行文件。 NASM 命令行上的-f elf 生成 32 位 ELF(-f elf64 生成 64 位对象)。您的 LD 命令行默认尝试生成 64 位可执行文件,因此会出现上述错误。您可以通过将-m elf_i386 选项添加到LD 的命令行来强制LD 生成32 位可执行文件。

ld:警告:找不到入口符号_start;默认为 00000000004000b0

你应该告诉 LD 你的入口点是 mainLD 默认查找 _start 的入口点。您可以在 LD 命令行中添加 -e main 来解决这个问题。

这样的错误提示你需要 C 库(存在 printf 的地方):

0_strange_calc.asm:(.text+0x8): undefined reference to `printf'

由于您的代码不直接使用 printf 我只能假设 training.s 中的函数需要它。为了在 C 库中进行链接,您需要在命令行中的 .o 文件之后添加它。您可以在 LD 命令行上使用 -lc 来执行此操作。您还需要具体告诉 LD 您需要使用哪个动态链接器库(在本例中为 32 位)。在 Debian 环境中,通常看起来像:-dynamic-linker /lib/ld-linux.so.2

所以你的 NASMLD 行应该是这样的:

nasm -f elf -g 0_strange_calc.asm
ld -melf_i386 -e main -dynamic-linker /lib/ld-linux.so.2 -o 0_strange_calc  0_strange_calc.o -lc

使用 GCC 方法

您可以通过使用 GCC 将您的目标文件链接到可执行文件来简化到 C 库的链接。要构建 32 位可执行文件,您可以使用:

nasm -f elf -g 0_strange_calc.asm
gcc -m32 0_strange_calc.o -o 0_strange_calc

C 库和运行时有一个 _start 方法,该方法执行 C 启动初始化,然后调用一个名为 main 恰好是您的程序集文件中的函数。 -m32 告诉 GCC 您还链接到 32 位可执行文件。


特殊注意事项

您可能还需要安装 Multlilib 版本的 gcc(如果需要,还可以安装 g++),以便您可以使用适当的 64 位 Debian 在 64 位 Debian 上正确构建和运行 32 位应用程序C 库。这可以通过这个命令行来完成:

apt-get install gcc-multilib g++-multilib

在您需要使用的基于 Ubuntu 的系统上:

sudo apt-get install gcc-multilib g++-multilib

【讨论】:

  • 似乎可以编译,但没有生成任何输出文件。我正在使用这个命令:` $ nasm -f elf -g 0_strange_calc.asm` ` ~$ ld -melf_i386 -e main -dynamic-linker /lib/ld-linux.so.2 -o known_calc 0_strange_calc.o -lc `
  • @Kaka 我给的原始命令行(我已经修复它)输出到一个名为strange_calc(不是0_strange_calc)的文件。那是我的一个错误。只需将其更改为ld -melf_i386 -e main -dynamic-linker /lib/ld-linux.so.2 -o 0_strange_calc 0_strange_calc.o -lc(输出文件只是错误的东西)
  • 是的,它生成了一个名为“strange_calc”的文件。现在我设法运行它。该应用程序似乎没有提供任何输出,但我想这是预期的结果。谢谢
  • 如果没有打印,可能是您的代码有问题。我不知道print_eax 是如何工作的,因为它不是给定代码的一部分。但是,如果您正在链接并获得可执行文件,那么如果您无法解决打印不正确的问题,最好在另一个问题中提出。
  • 我只需要输入两个数字。工作正常。
【解决方案2】:

请注意,问题不是asm 代码,而是缺少导入的函数。如果你读 training.s 你会看到printeax 的定义以及其他方法。此外,您会看到其中一些方法使用external function,例如printf,这当然不是asm 函数,而是一些导入的语言库

BITS 32
extern printf
extern exit
extern scanf
extern read

因此,为了使其工作 - 即找到那些外部库(您还在那里警告您应该处理,但这超出了这个范围)。您需要正确使用链接器。根据Franknasm board,你有两个选择

  1. 使用ld 链接器,但通过lc 选项告诉它使用c lib。即:ld -ld -o 0_strange_calc 0_strange_calc.o -lc。更多信息可以找到here

  2. 使用gcc链接器。

附言 请注意,代码还使用32bit,它会在您的计算机上产生警告,因为您可以使用64 bit,并且您可以使用elf 标志。更多信息请访问nasm docs

【讨论】:

  • 我不断收到cannot find -lcld,知道为什么吗? 它是否有可能与我使用 MinGW 工具包做某事?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
  • 2014-01-09
  • 2022-01-01
相关资源
最近更新 更多