用户输入和输出在我的汇编代码中不起作用 [英] User input and output doesn't work in my assembly code
问题描述
下面的程序编译没有错误,但运行时它不提示任何输入,也不打印任何内容.有什么问题,我该如何解决?
我使用这些命令来组装和链接:
/usr/local/bin/nasm -f macho32 $1ld -macosx_version_min 10.9.0 -lSystem -o 运行 $filename.o -e _start -lc
我的代码是:
section .data;换行字符串新行:db 0xa, 0xd长度:等于 $-NEWLINE.bss 节输入:resd 1节.text全局_start_开始:;读取字符移动 eax, 0x3移动 ebx, 0x1mov ecx, INPT移动 edx, 0x1整数 80 小时;打印字符移动 eax, 0x4移动 ebx, 0x1mov ecx, INPT移动 edx, 0x1整数 80 小时;输出后打印新行移动 eax, 0x4移动 ebx, 0x1mov ecx, NEWLINEmov edx, 长度整数 0x80;终止移动 eax, 0x1异或 ebx, ebx整数 0x80
您的代码中有迹象表明您在为 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).堆栈上该内存位置的值无关紧要.此要求是来自 旧的 UNIX 约定.
SYSCALL 号码及其参数的列表可以在 APPLE 头文件.您将需要这些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;换行字符串新行:db 0xa, 0xd长度:等于 $-NEWLINE.bss 节输入:resd 1全局_start节.text_开始:和 esp, -16 ;确保堆栈在程序开始时对齐 16 字节;在这个例子中没有必要,因为我们不调用;符合 OS/X 32 位 ABI 的外部函数推双字 1 ;读取 1 个字符推双字输入;输入缓冲器推双字 0 ;标准输入 = FD 0移动 eax, 3 ;系统调用 sys_read子 esp, 4 ;int 0x80 需要堆栈上的额外 4 个字节整数 0x80添加 esp, 16 ;恢复堆栈推双字 1 ;打印 1 个字符推双字输入;输出缓冲区 = 我们读入字符的缓冲区推双字 1 ;标准输出 = FD 1移动 eax, 4 ;系统调用 sys_write子 esp, 4 ;int 0x80 需要堆栈上的额外 4 个字节整数 0x80添加 esp, 16 ;恢复堆栈推双字长度;要写入的字符数推送双字新行;在 NEWLINE 字符串中写入数据推双字 1 ;标准输出 = FD 1移动 eax, 4 ;系统调用 sys_write子 esp, 4 ;int 0x80 需要堆栈上的额外 4 个字节整数 0x80添加 esp, 16 ;恢复堆栈推双字 0 ;程序返回值 = 0移动 eax, 1 ;系统调用 sys_exit子 esp, 4 ;int 0x80 需要堆栈上的额外 4 个字节整数 0x80
和 esp, -16
仅在您需要将堆栈对齐到 16 字节边界作为未来堆栈操作的基线时才需要.如果您打算调用符合 OS/X 32 位 ABI 堆栈预计在函数 CALL 之前以 16 字节对齐.对于通过 int 0x80
的系统调用,这种对齐不是必需的.
您应该能够组装并链接它:
nasm -f macho32 test.asm -o test.old -macosx_version_min 10.9.0 -o test test.o -e _start -lSystem
并运行它:
./test
The following program compiles without errors, but when run it doesn't prompt for any input and nothing prints. What's the problem, and how can I fix it?
I use these commands to assemble and link:
/usr/local/bin/nasm -f macho32 $1
ld -macosx_version_min 10.9.0 -lSystem -o run $filename.o -e _start -lc
My code is:
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
There are signs in your code that you may have been using a Linux tutorial when producing code for OS/X(BSD). Linux and OS/X have differing SYSCALL calling conventions. In OS/X 32-bit programs int 0x80
requires parameters (except the syscall in EAX) to be passed on a stack.
The important things to be aware of with 32-bit SYSCALLs via int 0x80
on OS/X are:
- arguments passed on the stack, pushed right-to-left
- you must allocate an additional 4 bytes (a DWORD) on the stack after you push all the arguments
- syscall number in the eax register
- call by interrupt 0x80
After pushing arguments on the stack in reverse order for int 0x80
you must allocate an additional 4 bytes (a DWORD) on the stack. The value in that memory location on the stack doesn't matter. This requirement is an artifact from an old UNIX convention.
A list of the SYSCALL numbers and their parameters can be found in the APPLE header files. You'll need these SYSCALLs:
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); }
I have commented some example code that would be similar in functionality to what you may have been attempting to achieve:
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
The and esp, -16
is only necessary if you need to align the stack to a 16-byte boundary as a baseline for future stack operations. If you intend to call external functions that conform to the OS/X 32-bit ABI the stack is expected to be 16-byte aligned immediately preceding a function CALL. This alignment is not necessary for system calls via int 0x80
.
You should be able to assemble and link it with:
nasm -f macho32 test.asm -o test.o
ld -macosx_version_min 10.9.0 -o test test.o -e _start -lSystem
And run it with:
./test
这篇关于用户输入和输出在我的汇编代码中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!