在x64程序集中存储键盘输入(Mac OS / X)

时间:2016-04-19 01:29:42

标签: macos assembly x86-64 gas

我已经尝试了一段时间从键盘获取数字并将其与堆栈上的值进行比较。如果它是正确的,它将打印" 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

1 个答案:

答案 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