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

Storing keyboard Input in x64 assembly (Mac OS/X)

一段时间以来,我一直在尝试从键盘获取数字并将其与堆栈中的值进行比较。如果正确,它会打印 "Hello World!",如果不正确,它应该打印 "Nope!"。然而,现在发生的是无论输入 "jne" 是否被调用,nope 是否被打印,以及段错误。也许你们中有人可以伸出援手。

.section __DATA,__data
    str:
      .asciz "Hello world!\n"

sto:
     .asciz "Nope!\n"

.section __TEXT,__text
.globl _main
_main:
    push %rbp
    mov %rsp,%rbp
    sub [=12=]x20, %rsp
    movl [=12=]x0, -0x4(%rbp)
    movl [=12=]x2, -0x8(%rbp)

    movl [=12=]x2000003, %eax
    mov [=12=], %edi
    subq [=12=]x4, %rsi
    movq %rsi, %rcx
    syscall

    cmp -0x8(%rbp), %edx
    je L1
    jne L2
    xor %rbx, %rbx
    xor %rax, %rax
    movl [=12=]x2000001, %eax          
    syscall

L1:
    xor %rax, %rax
    movl [=12=]x2000004, %eax         
    movl , %edi                 
    movq str@GOTPCREL(%rip), %rsi 
    movq , %rdx               
    syscall
    ret

L2:
    xor %eax, %eax
    movl [=12=]x2000004, %eax          
    movl , %edi                   
    movq sto@GOTPCREL(%rip), %rsi   
    movq , %rdx                 
    syscall
    ret

我会从这个开始 OS/X Syscall tutorial (The 64-bit part in your case). It is written for NASM syntax but the important information is the text and links for the SYSCALL calling convention. The SYSCALL table is found on this Apple webpage. Additional information on the standard calling convention for 64-bit OS/X can be found in the System V 64-bit ABI

SYSCALL 约定很重要:

  • arguments are passed in order via these registers rdi, rsi, rdx, r10, r8 and r9
  • syscall number in the rax register
  • the call is done via the syscall instruction
  • what OS X contributes to the mix is that you have to add 0x20000000 to the syscall number (still have to figure out why)

您的 sys_read 系统调用有很多问题。 SYSCALL table 表示:

3 AUE_NULL    ALL { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); } 

所以给定调用约定,int fdRDI中,user_addr_t cbuf(指向保存return数据的字符缓冲区的指针)是在 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

我做了其他小的清理,但试图保持代码的结构相似。您将必须学习更多汇编才能更好地理解设置 RSIsys_read SYSCALL 地址的代码。你应该试着找一个好的tutorial/book on x86-64 assembly language programming in general。写关于该主题的入门书超出了本答案的范围。

考虑到上述因素,可能更接近您所寻找的代码:

.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  [=13=]x20, %rsp          # Allocate 32 bytes of space on stack
                              #     for temp local variables

    movl [=13=]x2, -4(%rbp)       # Number for comparison

                              # 16-bytes from -20(%rbp) to -5(%rbp)
                              #     for char input buffer
    movl [=13=]x2000003, %eax
    mov [=13=], %edi              # 0 for STDIN
    lea -20(%rbp), %rsi       # Address of temporary buffer on stack
    mov , %edx             # Read 16 character maximum
    syscall

    movb (%rsi), %r10b        # RSI = pointer to buffer on stack
                              # get first byte
    subb , %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 [=13=]x2000004, %eax
    movl , %edi
    movq str@GOTPCREL(%rip), %rsi
    movq , %rdx
    syscall
    jmp L0                    # Jump to exit code

L2:                           # Print "Nope"
    xor %eax, %eax
    movl [=13=]x2000004, %eax
    movl , %edi
    movq sto@GOTPCREL(%rip), %rsi
    movq , %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