我正在尝试链接与yasm
汇总的单模块汇编语言程序,我从ld
收到以下错误:
Undefined symbols for architecture x86_64:
"start", referenced from:
implicit entry/start for main executable
(maybe you meant: _start)
ld: symbol(s) not found for inferred architecture x86_64
我实际上是在半定期的基础上得到这个错误,所以我想这是一个相当普遍的问题,但不知怎的,似乎没有人能得到满意的答案。在有人说这是前一个问题的副本之前,是的,我知道。正如你可以看到类似标题问题的巨大文本墙,看到这是重复的,我也可以。
Compiler Error: Undefined symbols for architecture x86_64
不适用于我的问题。我不是用C ++编写的,在那个问题中给出的解决方案对于那种语言来说是特殊的。
undefined symbol for architecture x86_64 in compiling C program
同样不能解决我的问题,因为我没有尝试将多个目标文件链接在一起。
Error Undefined symbols for architecture x86_64:
解决方案与高级语言中的特定框架有关。
Compiler Error: Undefined symbols for architecture x86_64
解决方案涉及修复函数原型。由于显而易见的原因,此处不适用。
......你明白了。我能找到的每一个过去的问题都是通过一些不适用于我的情况的特殊方法来解决的。
请帮我解决这个问题。我已经厌倦了一次又一次地得到这个错误而无法对它做任何事情,因为它的记录很差。恕我直言,世界迫切需要一个GNU Dev Tools等效的MS-DOS错误代码参考手册。
其他信息:
操作系统:Mac OS X El Capitain
来源列表:
segment .text
global _start
_start:
mov eax,1 ; 1 is the syscall number for exit
mov ebx,5 ; 5 is the value to return
int 0x80 ; execute a system call
目标文件的Hexdump,表明该符号确实是_start
而不是start
:
00000000 cf fa ed fe 07 00 00 01 03 00 00 00 01 00 00 00 |................|
00000010 02 00 00 00 b0 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 19 00 00 00 98 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 0c 00 00 00 00 00 00 00 d0 00 00 00 00 00 00 00 |................|
00000050 0c 00 00 00 00 00 00 00 07 00 00 00 07 00 00 00 |................|
00000060 01 00 00 00 00 00 00 00 5f 5f 74 65 78 74 00 00 |........__text..|
00000070 00 00 00 00 00 00 00 00 5f 5f 54 45 58 54 00 00 |........__TEXT..|
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000090 0c 00 00 00 00 00 00 00 d0 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 |................|
000000b0 00 00 00 00 00 00 00 00 02 00 00 00 18 00 00 00 |................|
000000c0 dc 00 00 00 01 00 00 00 ec 00 00 00 08 00 00 00 |................|
000000d0 b8 01 00 00 00 bb 05 00 00 00 cd 80 01 00 00 00 |................|
000000e0 0f 01 00 00 00 00 00 00 00 00 00 00 00 5f 73 74 |............._st|
000000f0 61 72 74 00 |art.|
000000f4
答案 0 :(得分:7)
代码:
segment .text
global _start
_start:
mov eax,1 ; 1 is the syscall number for exit
mov ebx,5 ; 5 is the value to return
int 0x80 ; execute a system call
建议您使用的是32位Linux教程。我得出了这个结论,因为32-bit Linux ABI使用寄存器通过int 0x80
将参数传递给内核。 OS / X不同。您传递堆栈上的参数(从右向左传递)。在32位OS / X中,它看起来像:
global start
section .text
start:
; sys_write syscall
; See: https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master
; 4 AUE_NULL ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); }
push dword msg.len ; Last argument is length
push dword msg ; 2nd last is pointer to string
push dword 1 ; 1st argument is File descriptor (1=STDOUT)
mov eax, 4 ; eax = 4 is write system call
sub esp, 4 ; On OS/X 32-bit code always need to allocate 4 bytes on stack
int 0x80
; sys_exit
; 1 AUE_EXIT ALL { void exit(int rval); }
push dword 42 ; Return value
mov eax, 1 ; eax=1 is exit system call
sub esp, 4 ; allocate 4 bytes on stack
int 0x80
section .rodata
msg: db "Hello, world!", 10
.len: equ $ - msg
汇总并链接:
nasm -f macho testexit.asm
ld -macosx_version_min 10.7.0 -o testexit testexit.o
./testexit
echo $?
YASM 参数应与 NASM 相同。它应输出:
Hello, world! 42
32位OS / X代码中系统调用的经验法则:
int 0x80
不需要16字节对齐的堆栈在推送参数之后和系统调用之前,需要在堆栈上分配额外的4个字节。例子:
sub esp, 4
push eax
EAX 注册表中的系统电话号码
int 0x80
Apple在他们的website上记录了OS / X系统调用。
64位OS / X几乎使用与64位Linux相同的内核调用约定。 64-bit Linux System V ABI适用于系统调用。特别是 A.2 AMD64 Linux内核约定部分。该部分有以下规则:
- 用户级应用程序用作整数寄存器来传递序列 %rdi,%rsi,%rdx,%rcx,%r8和%r9。内核接口使用%rdi, %rsi,%rdx,%r10,%r8和%r9。
- 系统调用通过syscall指令完成。内核破坏了 注册%rcx和%r11。
- 系统调用的号码必须在寄存器%rax中传递。
- 系统调用仅限于六个参数,不直接传递参数 堆栈。
- 从系统调用返回,寄存器%rax包含结果 系统调用。介于-4095和-1之间的值表示错误, 它是-errno。
- 只将类INTEGER或类MEMORY的值传递给内核。
醇>
64位OS / X使用与32位OS / X相同的System Call numbers,但是所有数字都必须添加0x02000000。可以修改上面的代码以用作64位OS / X程序:
global start
section .text
start:
mov eax, 0x2000004 ; write system call
mov edi, 1 ; stdout = 1
mov rsi, msg ; address of the message to print
;lea rsi, [rel msg]; Alternative way using RIP relative addressing
mov edx, msg.len ; length of message
syscall ; Use syscall, NOT int 0x80
mov eax, 0x2000001 ; exit system call
mov edi, 42 ; return 42 when exiting
syscall
section .rodata
msg: db "Hello, world!", 10
.len: equ $ - msg
请注意,写入32位寄存器时,CPU会自动将零扩展到64位寄存器。上面的代码通过写入 EAX , EDI 而不是 RAX 和 RDI 等寄存器来使用此功能。您可以使用64位寄存器,但使用32位寄存器会在代码中保存一个字节。
汇总并链接:
nasm -f macho64 testexit64.asm
ld -macosx_version_min 10.7.0 -lSystem -o testexit64 testexit64.o
./testexit64
echo $?
应输出:
Hello, world! 42
注意:其中一些信息在本质上与此OS/X tutorial类似,但修正了一些更正和编码错误。