【问题标题】:User input and output doesn't work in my assembly code用户输入和输出在我的汇编代码中不起作用
【发布时间】:2023-03-09 04:48:01
【问题描述】:

以下程序编译时没有错误,但运行时它不会提示输入任何内容,也不会打印任何内容。有什么问题,我该如何解决?

我使用这些命令来组装和链接:

/usr/local/bin/nasm -f macho32 $1
ld -macosx_version_min 10.9.0 -lSystem -o run $filename.o -e _start -lc

我的代码是:

section .data
    ;New line string
    NEWLINE: db 0xa, 0xd
    LENGTH: equ $-NEWLINE

section .bss    
INPT: resd 1

section .text   
global _start
_start:


;Read character
mov eax, 0x3
mov ebx, 0x1
mov ecx, INPT
mov edx, 0x1
int 80h

;print character
mov eax, 0x4
mov ebx, 0x1
mov ecx, INPT
mov edx, 0x1
int 80h

;Print new line after the output 
mov eax, 0x4
mov ebx, 0x1
mov ecx, NEWLINE
mov edx, LENGTH
int 0x80

;Terminate
mov eax, 0x1
xor ebx, ebx
int 0x80

【问题讨论】:

  • int 0x80 在 OSX 上的工作方式不同。 int 0x80 的参数(除了 EAX)以 32 位代码而不是寄存器的形式在堆栈上传递。您编写的代码看起来像是为 Linux 编写的。我推荐一个 OS/X tutorial 。 Linux 和 OSX 之间的系统调用号也不同。
  • 一旦将代码转换为 OS/X,您应该知道标准输入是文件描述符 0,标准输出是文件描述符 1。您对两个输入都使用标准输出 (1)和要求问题的输出。
  • @Michael Petch 是的,你是对的,谢谢!

标签: macos assembly x86 nasm system-calls


【解决方案1】:

您的代码中有迹象表明您在为 OS/X(BSD) 编写代码时可能一直在使用 Linux 教程。 Linux 和 OS/X 有不同的 SYSCALL 调用约定。在 OS/X 32 位程序中,int 0x80 需要在堆栈上传递参数(EAX 中的系统调用除外)。

在 OS/X 上通过 int 0x80 使用 32 位 SYSCALL 需要注意的重要事项是:

  • 在堆栈上传递的参数,从右向左推
  • 压入所有参数后,您必须在堆栈上额外分配 4 个字节(DWORD
  • eax 寄存器中的系统调用号
  • 通过中断 0x80 调用

在为int 0x80 以相反的顺序将参数压入堆栈后,您必须在堆栈上分配额外的 4 个字节(DWORD)。堆栈上该内存位置的值无关紧要。此要求是来自old UNIX convention 的工件。

SYSCALL 编号及其参数的列表可以在 APPLE header files 中找到。您将需要这些 SYSCALL

1 AUE_EXIT    ALL { void exit(int rval); }
3 AUE_NULL    ALL { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); } 
4 AUE_NULL    ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } 

我已经注释了一些示例代码,这些示例代码在功能上与您可能试图实现的功能相似:

section .data
    ;New line string
    NEWLINE: db 0xa, 0xd
    LENGTH: equ $-NEWLINE

section .bss
    INPT: resd 1

global _start

section .text
_start:
    and     esp, -16      ; Make sure stack is 16 byte aligned at program start
                          ;     not necessary in this example since we don't call 
                          ;     external functions that conform to the OS/X 32-bit ABI

    push    dword 1       ; Read 1 character
    push    dword INPT    ; Input buffer
    push    dword 0       ; Standard input = FD 0
    mov     eax, 3        ; syscall sys_read
    sub     esp, 4        ; Extra 4 bytes on stack needed by int 0x80
    int     0x80
    add     esp, 16       ; Restore stack

    push    dword 1       ; Print 1 character
    push    dword INPT    ; Output buffer = buffer we read characters into
    push    dword 1       ; Standard output = FD 1
    mov     eax, 4        ; syscall sys_write
    sub     esp, 4        ; Extra 4 bytes on stack needed by int 0x80
    int     0x80
    add     esp, 16       ; Restore stack

    push    dword LENGTH  ; Number of characters to write
    push    dword NEWLINE ; Write the data in the NEWLINE string
    push    dword 1       ; Standard output = FD 1
    mov     eax, 4        ; syscall sys_write
    sub     esp, 4        ; Extra 4 bytes on stack needed by int 0x80
    int     0x80
    add     esp, 16       ; Restore stack

    push    dword 0       ; Return value from program = 0
    mov     eax, 1        ; syscall sys_exit
    sub     esp, 4        ; Extra 4 bytes on stack needed by int 0x80
    int     0x80

and esp, -16 仅在您需要将堆栈对齐到 16 字节边界作为未来堆栈操作的基线时才需要。如果您打算调用符合OS/X 32-bit ABI 的外部函数,则堆栈应在函数CALL 之前与16 字节对齐。通过int 0x80 进行的系统调用不需要这种对齐方式。

您应该能够将其组装并链接到:

nasm -f macho32 test.asm -o test.o
ld -macosx_version_min 10.9.0 -o test test.o -e _start -lSystem

然后运行它:

./test

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-10
    • 1970-01-01
    • 1970-01-01
    • 2014-11-07
    • 2023-02-06
    相关资源
    最近更新 更多