在程序集中访问参数
Accessing parameters in Assembly
概览
我正在用 x86 汇编 (NASM) 编写一个程序,它基本上从用户那里得到一个股息和除数,然后调用一个程序来进行除法,返回 EAX 中的值供我打印.我将 Paul Carter 的 asm_io.inc
库用于 C I/O 函数 (http://pacman128.github.io/pcasm/)。这是我在命令行中输入的用于获取程序 运行 的内容:
nasm -f win32 source.asm
gcc source.obj driver.c asm_io.obj
.
问题
现在的问题是,当我将两个参数传递给过程(称为 divide
)时,我尝试通过间接访问参数(例如 [ebp + 8]
用于第一个参数),但是它会产生内存地址代替。我试过调试它,但无济于事。是不是我做错了什么导致了错误的结果?我的代码:
%include "asm_io.inc"
segment .data
prompt1 db "Enter a dividend: ", 0
prompt2 db "Enter a divisor: ", 0
answer1 db " divided by ", 0
answer2 db " equals ", 0
segment .bss
dividend resd 1
divisor resd 1
segment .text
global _asm_main
_asm_main:
enter 0,0
pusha
mov eax, prompt1
call print_string
call read_int
mov [dividend], eax
mov eax, prompt2
call print_string
call read_int
mov [divisor], eax
mov eax, [dividend]
call print_int
mov eax, answer1
call print_string
mov eax, [divisor]
call print_int
mov eax, answer2
call print_string
push dword dividend
push dword divisor
call divide
add esp, 8
call print_int
popa
mov eax, 0
leave
ret
divide:
push ebp
mov ebp, esp
mov eax, [ebp + 8]
div dword [ebp + 4]
pop ebp
ret
使用 push
指令,您突然放弃了间接寻址并要求它简单地推送地址。根据先前的说明(例如 mov eax,[divisor]
,您确实要求间接访问。
push dword dividend
push dword divisor
在NASM中这些指令将推送变量的地址。您需要使用方括号来获取它们的实际值。
push dword [dividend]
push dword [divisor]
您的除法例程在执行div
指令之前忘记将edx
寄存器归零!
您的 除法 例程当前将 除数 除以 return 地址.
位移相差 4。这是正确的代码:
divide:
push ebp
mov ebp, esp
mov eax, [ebp + 12] ; Dividend
xor edx, edx
div dword [ebp + 8] ; Divisor
pop ebp
ret
您当然可以选择在子例程中传递地址和取消引用:
divide:
push ebp
mov ebp, esp
mov ecx, [ebp + 8] ; Address of Divisor
mov ecx, [ecx]
mov eax, [ebp + 12] ; Address of Dividend
mov eax, [eax]
xor edx, edx
div ecx
pop ebp
ret
概览
我正在用 x86 汇编 (NASM) 编写一个程序,它基本上从用户那里得到一个股息和除数,然后调用一个程序来进行除法,返回 EAX 中的值供我打印.我将 Paul Carter 的 asm_io.inc
库用于 C I/O 函数 (http://pacman128.github.io/pcasm/)。这是我在命令行中输入的用于获取程序 运行 的内容:
nasm -f win32 source.asm
gcc source.obj driver.c asm_io.obj
.
问题
现在的问题是,当我将两个参数传递给过程(称为 divide
)时,我尝试通过间接访问参数(例如 [ebp + 8]
用于第一个参数),但是它会产生内存地址代替。我试过调试它,但无济于事。是不是我做错了什么导致了错误的结果?我的代码:
%include "asm_io.inc"
segment .data
prompt1 db "Enter a dividend: ", 0
prompt2 db "Enter a divisor: ", 0
answer1 db " divided by ", 0
answer2 db " equals ", 0
segment .bss
dividend resd 1
divisor resd 1
segment .text
global _asm_main
_asm_main:
enter 0,0
pusha
mov eax, prompt1
call print_string
call read_int
mov [dividend], eax
mov eax, prompt2
call print_string
call read_int
mov [divisor], eax
mov eax, [dividend]
call print_int
mov eax, answer1
call print_string
mov eax, [divisor]
call print_int
mov eax, answer2
call print_string
push dword dividend
push dword divisor
call divide
add esp, 8
call print_int
popa
mov eax, 0
leave
ret
divide:
push ebp
mov ebp, esp
mov eax, [ebp + 8]
div dword [ebp + 4]
pop ebp
ret
使用 push
指令,您突然放弃了间接寻址并要求它简单地推送地址。根据先前的说明(例如 mov eax,[divisor]
,您确实要求间接访问。
push dword dividend push dword divisor
在NASM中这些指令将推送变量的地址。您需要使用方括号来获取它们的实际值。
push dword [dividend]
push dword [divisor]
您的除法例程在执行div
指令之前忘记将edx
寄存器归零!
您的 除法 例程当前将 除数 除以 return 地址.
位移相差 4。这是正确的代码:
divide:
push ebp
mov ebp, esp
mov eax, [ebp + 12] ; Dividend
xor edx, edx
div dword [ebp + 8] ; Divisor
pop ebp
ret
您当然可以选择在子例程中传递地址和取消引用:
divide:
push ebp
mov ebp, esp
mov ecx, [ebp + 8] ; Address of Divisor
mov ecx, [ecx]
mov eax, [ebp + 12] ; Address of Dividend
mov eax, [eax]
xor edx, edx
div ecx
pop ebp
ret