我正在为处理器架构使用yasm
汇编程序。x86_64
假设我已经在该部分中定义了三个数字.data
:
section .data
;CONSTANTS:
SYSTEM_EXIT equ 60
SUCCESS_EXIT equ 0
;VARIABLES:
dVar1 dd 40400
wVar2 dw -234
bVar3 db -23
dRes dd 0 ;quotient
dRem dd 0 ;reminder
我想要做的是将有符号双字dVar1
乘以有符号字,dVar2
然后再除以有符号字节bVar3
。
下面我将参考本书介绍我的“解决方案”,以了解我为什么要执行每个步骤。问题在文末。
dVar1 * wVar2(有符号)
我没有看到任何明确的规则,即乘法仅适用于相同大小的数字。但是看到一些隐含的。这就是为什么我使用转换wVar2
:
movsx eax, word [wVar2] ;[wVar2] now in eax
现在“它们”的大小相同,所以我只是将它们相乘:
imul dword [dVar1] ;edx:eax = eax * [dVar1]
...例如,将ax(16 位)乘以字操作数(也是 16 位)的结果提供双字(32 位)结果。然而,结果并没有放在eax中(这可能更容易),它放在两个寄存器中,dx用于高阶结果(16 位)和ax用于低阶结果(16 位),通常写为dx:ax(按照惯例)。
正如我正确理解的那样,结果现在在edx:eax
.
edx:eax / bVar3(签名)
...被除数需要D寄存器(用于高阶部分)和A(用于低阶部分)...如果执行了先前的乘法,则D和A寄存器可能已经正确设置(这是我的案例[OP的注释])。
和
...此外,必须将A以及可能的D寄存器组合用于被除数。
- Byte Divide: ax for 16-bits
- 字除法:dx:ax用于 32 位
- 双字除法:edx:eax用于 64 位(这是我的情况 [OP's note])
- 四字除法:rdx:rax for 128-bits
因此,最初我转换bVar3
为双字,然后将其分开:
movsx ebx, byte [bVar3] ;ebx = [bVar3]
idiv ebx, ;eax = edx:eax / [bVar3]
整个代码然后
section .data
;CONSTANTS:
SYSTEM_EXIT equ 60
SUCCESS_EXIT equ 0
;VARIABLES:
dVar1 dd 40400
wVar2 dw -234
bVar3 db -23
dRes dd 0 ;quotient
dRem dd 0 ;reminder
section .text
global _start
_start:
movsx ebx, byte [bVar3] ;conversion to double-word
movsx eax, word [wVar2] ;conversion to double-word
imul dword [dVar1] ;edx:eax = eax * [dVar1]
idiv ebx ;eax = edx:eax / [bVar3], edx = edx:eax % [bVar3]
mov dword [dRes], eax
mov dword [dRem], edx
last:
mov rax, SYSTEM_EXIT
mov rdi, SUCCESS_EXIT
syscall
我使用调试器并查看正确答案:
(gdb) x/dw &dRes
0x600159: 411026
(gdb) x/dw &dRem
0x60015d: -2
但我不确定以下几点。
- 真的有必要做我做过的那些步骤吗?它是“尽可能少的行数”解决方案吗?
- 这是正确的解决方案吗?我的意思是我可能在这里犯了一个错误或错过了一些重要的事情。
PS 也许这个问题更可能是 CodeReview SE 问题。如果你也这么认为,请告诉我。