链接汇编程序:错误 "undefined reference to `printf'"
Linking an assembler program: error "undefined reference to `printf'"
我正在尝试在 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中已经转换成功,其他简单的代码我编译和链接都没有问题。我究竟做错了什么?我该如何解决?
请注意,问题不在于 asm
代码,而是缺少导入函数。如果你读
training.s 你会看到 printeax
和其他方法的定义。此外,您会看到其中一些方法使用 external function
,例如 printf
,这当然不是 asm
函数,而是一些导入的语言库
BITS 32
extern printf
extern exit
extern scanf
extern read
所以为了让它工作 - 即找到那些外部库(你也在那里警告你应该处理但这不在这个范围内)。您需要正确使用链接器。根据 Frank
在 nasm board 你有两个选择
使用 ld
链接器,但通过 lc
选项告诉它使用 c
库。即:ld -ld -o 0_strange_calc 0_strange_calc.o -lc
。可以找到更多信息 here
使用 gcc
链接器。
P.S
请注意,该代码还使用了 32bit
,它在您的计算机上会产生警告,因为您可以使用 64 bit
并使用 elf
标志。您可以在 nasm docs
找到更多相关信息
你有几个选择
- 使用LD到link到最终的可执行文件
- 使用 GCC 到 link 到最终的可执行文件
使用 LD 方法
您的命令行使用 LD,不幸的是,这会带来一些问题。第一个:
ld: i386 architecture of input file `0_strange_calc.o' is incompatible with i386:x86-6
您正在使用 64 位 Debian,试图生成 32 位可执行文件。 NASM 命令行上的 -f elf
生成 32 位 ELF(-f elf64
生成 64 位对象)。您的 LD 命令行默认尝试生成 64 位可执行文件,因此会出现上述错误。您可以通过在 LD 的命令行中添加 -m elf_i386
选项来强制 LD 生成 32 位可执行文件。
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
您应该告诉 LD 您的入口点是 main 。 LD 默认查找 _start 的入口点。您可以将 -e main
添加到 LD 命令行来解决这个问题。
这样的错误表明您需要 C 库(其中存在 printf):
0_strange_calc.asm:(.text+0x8): undefined reference to `printf'
由于您的代码不直接使用 printf 我只能假设 training.s
中的函数需要它。为了 C 库中的 link,您需要在命令行中的 .o
文件之后添加它。您可以在 LD 命令行上使用 -lc
来执行此操作。您还需要明确告诉 LD 您将需要使用哪个动态 linker 库(在本例中为 32 位库)。在 Debian 环境中,通常看起来像:-dynamic-linker /lib/ld-linux.so.2
因此您的 NASM 和 LD 行应该如下所示:
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 将 linking 简化为 C 库 link 您的对象文件到可执行文件。要构建 32 位可执行文件,您可以使用:
nasm -f elf -g 0_strange_calc.asm
gcc -m32 0_strange_calc.o -o 0_strange_calc
C 库和 运行time 有一个 _start 方法执行 C 启动初始化,然后调用一个名为 main 的函数,该函数恰好是您的汇编文件中的函数。 -m32
告诉 GCC 你也在 linking 到 32 位可执行文件。
特殊注意事项
您可能还需要安装 Multlilib 版本的 gcc(如果需要,还可以安装 g++),以便您可以正确构建和 运行 32 位64 位 Debian 上的应用程序使用适当的 C 库。这可以用这个命令行来完成:
apt-get install gcc-multilib g++-multilib
在基于 Ubuntu 的系统上,您需要使用:
sudo apt-get install gcc-multilib g++-multilib
我正在尝试在 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中已经转换成功,其他简单的代码我编译和链接都没有问题。我究竟做错了什么?我该如何解决?
请注意,问题不在于 asm
代码,而是缺少导入函数。如果你读
training.s 你会看到 printeax
和其他方法的定义。此外,您会看到其中一些方法使用 external function
,例如 printf
,这当然不是 asm
函数,而是一些导入的语言库
BITS 32
extern printf
extern exit
extern scanf
extern read
所以为了让它工作 - 即找到那些外部库(你也在那里警告你应该处理但这不在这个范围内)。您需要正确使用链接器。根据 Frank
在 nasm board 你有两个选择
使用
ld
链接器,但通过lc
选项告诉它使用c
库。即:ld -ld -o 0_strange_calc 0_strange_calc.o -lc
。可以找到更多信息 here使用
gcc
链接器。
P.S
请注意,该代码还使用了 32bit
,它在您的计算机上会产生警告,因为您可以使用 64 bit
并使用 elf
标志。您可以在 nasm docs
你有几个选择
- 使用LD到link到最终的可执行文件
- 使用 GCC 到 link 到最终的可执行文件
使用 LD 方法
您的命令行使用 LD,不幸的是,这会带来一些问题。第一个:
ld: i386 architecture of input file `0_strange_calc.o' is incompatible with i386:x86-6
您正在使用 64 位 Debian,试图生成 32 位可执行文件。 NASM 命令行上的 -f elf
生成 32 位 ELF(-f elf64
生成 64 位对象)。您的 LD 命令行默认尝试生成 64 位可执行文件,因此会出现上述错误。您可以通过在 LD 的命令行中添加 -m elf_i386
选项来强制 LD 生成 32 位可执行文件。
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
您应该告诉 LD 您的入口点是 main 。 LD 默认查找 _start 的入口点。您可以将 -e main
添加到 LD 命令行来解决这个问题。
这样的错误表明您需要 C 库(其中存在 printf):
0_strange_calc.asm:(.text+0x8): undefined reference to `printf'
由于您的代码不直接使用 printf 我只能假设 training.s
中的函数需要它。为了 C 库中的 link,您需要在命令行中的 .o
文件之后添加它。您可以在 LD 命令行上使用 -lc
来执行此操作。您还需要明确告诉 LD 您将需要使用哪个动态 linker 库(在本例中为 32 位库)。在 Debian 环境中,通常看起来像:-dynamic-linker /lib/ld-linux.so.2
因此您的 NASM 和 LD 行应该如下所示:
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 将 linking 简化为 C 库 link 您的对象文件到可执行文件。要构建 32 位可执行文件,您可以使用:
nasm -f elf -g 0_strange_calc.asm
gcc -m32 0_strange_calc.o -o 0_strange_calc
C 库和 运行time 有一个 _start 方法执行 C 启动初始化,然后调用一个名为 main 的函数,该函数恰好是您的汇编文件中的函数。 -m32
告诉 GCC 你也在 linking 到 32 位可执行文件。
特殊注意事项
您可能还需要安装 Multlilib 版本的 gcc(如果需要,还可以安装 g++),以便您可以正确构建和 运行 32 位64 位 Debian 上的应用程序使用适当的 C 库。这可以用这个命令行来完成:
apt-get install gcc-multilib g++-multilib
在基于 Ubuntu 的系统上,您需要使用:
sudo apt-get install gcc-multilib g++-multilib