我已经尝试了一段时间从键盘获取数字并将其与堆栈上的值进行比较。如果它是正确的,它将打印" Hello World!"如果不正确,它应该打印出来#34;不要!"。然而,现在发生的事情无论输入是什么,而且#34; jne"被称为,打印nope和segfault。也许你们其中一个人可以伸出援助之手。
.section __DATA,__data
str:
.asciz "Hello world!\n"
sto:
.asciz "Nope!\n"
.section __TEXT,__text
.globl _main
_main:
push %rbp
mov %rsp,%rbp
sub $0x20, %rsp
movl $0x0, -0x4(%rbp)
movl $0x2, -0x8(%rbp)
movl $0x2000003, %eax
mov $0, %edi
subq $0x4, %rsi
movq %rsi, %rcx
syscall
cmp -0x8(%rbp), %edx
je L1
jne L2
xor %rbx, %rbx
xor %rax, %rax
movl $0x2000001, %eax
syscall
L1:
xor %rax, %rax
movl $0x2000004, %eax
movl $1, %edi
movq str@GOTPCREL(%rip), %rsi
movq $14, %rdx
syscall
ret
L2:
xor %eax, %eax
movl $0x2000004, %eax
movl $1, %edi
movq sto@GOTPCREL(%rip), %rsi
movq $6, %rdx
syscall
ret
答案 0 :(得分:1)
我会从这个OS/X Syscall tutorial开始(在你的情况下是64位部分)。它是为NASM语法编写的,但重要信息是 SYSCALL 调用约定的文本和链接。 SYSCALL 表位于此Apple webpage上。有关64位OS / X标准调用约定的更多信息,请参见System V 64-bit ABI。
SYSCALL 约定的重要性:
- 参数通过这些寄存器rdi,rsi,rdx,r10,r8和r9按顺序传递
- rax寄存器中的系统调用号
- 通过系统调用指令
完成调用- OS X对混合的影响是你必须在系统调用号码中添加0x20000000(仍然要弄清楚原因)
您的sys_read
系统调用存在许多问题。 SYSCALL 表说明了这一点:
3 AUE_NULL ALL { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); }
因此,根据调用约定,int fd
位于 RDI 中,user_addr_t cbuf
(指向保存返回数据的字符缓冲区的指针)位于 RSI 中,user_size_t nbyte
(缓冲区可以包含的最大字节数)在 RDX 中。
您的程序在ret
上出现故障,因为您没有正确的功能结尾来匹配顶部的功能序言:
push %rbp #
mov %rsp,%rbp # Function prologue
您需要在底部执行相反操作,在 RAX 中设置结果代码,然后执行ret
。类似的东西:
mov %rbp,%rsp # \ Function epilogue
pop %rbp # /
xor %eax, %eax # Return value = 0
ret # Return to C runtime which will exit
# gracefully and return to OS
我做了其他次要的清理,但试图保持代码的结构相似。您必须学习更多汇编,以便更好地理解使用sys_read
SYSCALL 的地址设置 RSI 的代码。您应该尝试在x86-64汇编语言编程中找到一本很好的教程/书。撰写关于该主题的入门书超出了这个答案的范围。
可能更接近您所寻找的代码将上述内容考虑在内:
.section __DATA,__data
str:
.asciz "Hello world!\n"
sto:
.asciz "Nope!\n"
.section __TEXT,__text
.globl _main
_main:
push %rbp #
mov %rsp,%rbp # Function prologue
sub $0x20, %rsp # Allocate 32 bytes of space on stack
# for temp local variables
movl $0x2, -4(%rbp) # Number for comparison
# 16-bytes from -20(%rbp) to -5(%rbp)
# for char input buffer
movl $0x2000003, %eax
mov $0, %edi # 0 for STDIN
lea -20(%rbp), %rsi # Address of temporary buffer on stack
mov $16, %edx # Read 16 character maximum
syscall
movb (%rsi), %r10b # RSI = pointer to buffer on stack
# get first byte
subb $48, %r10b # Convert first character to number 0-9
cmpb -4(%rbp), %r10b # Did we find magic number (2)?
jne L2 # If No exit with error message
L1: # If the magic number matched print
# Hello World
xor %rax, %rax
movl $0x2000004, %eax
movl $1, %edi
movq str@GOTPCREL(%rip), %rsi
movq $14, %rdx
syscall
jmp L0 # Jump to exit code
L2: # Print "Nope"
xor %eax, %eax
movl $0x2000004, %eax
movl $1, %edi
movq sto@GOTPCREL(%rip), %rsi
movq $6, %rdx
syscall
L0: # Code to exit main
mov %rbp,%rsp # \ Function epilogue
pop %rbp # /
xor %eax, %eax # Return value = 0
ret # Return to C runtime which will exit
# gracefully and return to OS