我正在通过paul caurter从PC Assembly学习80386
mul source
Run Code Online (Sandbox Code Playgroud)
- 如果操作数是字节大小,则将其乘以AL寄存器中的字节,结果存储在AX的16位中.
精细.
- 如果源是16位,则将其乘以AX中的字,32位结果存储在DX:AX中.
Q1:为什么选择DX:AX?为什么它不能存储在EAX/EDX中?
imul 真是令人困惑
imul dest, source1
imul dest, source1, source2
Run Code Online (Sandbox Code Playgroud)
alt text http://img697.imageshack.us/img697/8976/imul.gif
我在理解表格方面遇到了问题.
Q2:在表的第2个条目中.再次,为什么DX:AX.为什么不EAX或EDX?
现在考虑以下代码片段:
imul eax ; edx:eax = eax * eax
mov ebx, eax ; save answer in ebx
mov eax, square_msg ; square_msg db "Square of input is ", 0
call print_string ; prints the string eax
mov eax, ebx
call print_int ; prints the int stored in eax
call print_nl ; prints new line
Run Code Online (Sandbox Code Playgroud)
Q3:它预先说过,The notation EDX:EAX means to think of the EDX and EAX registers as one 64 bit register with the upper
32 bits in EDX and the lower bits in EAX.所以答案也存放在edx中,对吧?在上面的代码中我们没有考虑任何EDX,我们只是指EAX如何仍然有效?
问题4:我对表中所有条目的其余部分都有疑问.两个n位数(n = 8/16/32位)的最坏情况乘法结果是2n位.为什么它将两个16/32位乘法的结果存储在相同大小的寄存器本身?
Q1/Q2:x86指令集保持其16位历史记录.进行16位乘法时,答案存储在DX:AX中.这就是它的方式,因为它就是16位的土地.
问题3:如果您尝试计算大于2 ^ 16的数字的平方,则显示的代码存在错误,因为代码忽略了存储的结果的高32位edx.
问题4:我想你可能会误读表格.8位乘法存储在16位结果中; 16位乘法存储在32位结果中; 32位乘法存储在64位结果中.你指的是哪一行?
imul指令有很多不同的变化。2位代码。
您偶然发现的变量是16位乘法。它将AX寄存器与作为imul参数传递的任何值相乘,并将结果存储在DX:AX中。
一个32位变体的工作方式类似于16位乘法,但是将寄存器写入EDX:EAX。要使用此变体,您要做的就是使用32位参数。
例如:
; a 16 bit multiplication:
mov ax, [factor1]
mov bx, [factor2]
imul bx ; 32-bit result in DX:AX
; or imul word [factor2]
; a 32 bit multiplication:
mov eax, [factor1]
mov ebx, [factor2]
imul ebx ; 64-bit result in EDX:EAX
Run Code Online (Sandbox Code Playgroud)
在386或更高版本上,您还可以编写imul两个操作数形式的。这使得它更加灵活和易于使用。在该变体中,您可以自由选择任意两个寄存器作为源和目标,并且CPU不会浪费时间在任何地方写入上半部分的结果。并且不会破坏EDX。
mov ecx, [factor1]
imul ecx, [factor2] ; result in ecx, no other registers affected
imul ecx, ecx ; and square the result
Run Code Online (Sandbox Code Playgroud)
或为带符号的16位输入匹配您的imul。(将movzx用于无符号输入)
movsx ecx, word [factor1]
movsx eax, word [factor2] ; sign-extend inputs to 32-bit
imul eax, ecx ; 32-bit multiply, result in EAX
imul eax, eax ; and square the result
Run Code Online (Sandbox Code Playgroud)
imul的此变体在386中引入,并提供16位和32位操作数大小。(以及64位模式下的64位操作数大小)。
在32位代码中,您始终可以假定有386条类似imul reg, reg/mem的指令可用,但是如果您不关心较旧的CPU,则可以在16位代码中使用它。
286引入了3操作数立即数形式。
imul cx, bx, 123 ; requires 286
imul ecx, ebx, 123 ; requires 386
Run Code Online (Sandbox Code Playgroud)
Q1/Q2:为什么是 DX:AX ?为什么它不能存储在 EAX / EDX 中?
就像其他人说的那样,这只是为了向后兼容。最初的(i)mul指令是从16位x86其来意长的32位x86指令集出现过,所以他们不能把结果存储到EAX / EDX,因为没有E-寄存器。
Q3:在上面的代码中,我们没有考虑任何 EDX 我们只是指 EAX 这如何仍然有效?
您输入了不会导致结果溢出的小值,因此您没有看到差异。如果您使用足够大的值(>= 16 位),您将看到 EDX != 0 并且打印结果将不正确。
Q4:它怎么把两个16/32位相乘的结果存储在本身相同大小的寄存器中?
并不是结果仍然与操作数的大小相同。将两个 n 位值相乘总是产生一个 2n 位值。但是在imul r16, r/m16[, imm8/16]和它们的 32/64 位对应项中,高 n 位结果被丢弃。当您只需要结果的低 16/32/64 位(即非加宽乘法)时,或者当您可以确保结果不会溢出时,就会使用它们。
- 双操作数形式——在这种形式下,目标操作数(第一个操作数)乘以源操作数(第二个操作数)。目标操作数是通用寄存器,源操作数是立即数、通用寄存器或内存位置。中间积(输入操作数的两倍)被截断并存储在目标操作数位置。
- [... 三操作数形式相同]
现在的现代编译器几乎只将多操作数imul用于有符号和无符号乘法,因为
intx int? int, longx long? long...),它非常适合imul的操作数。只有这样,才能强制编译器以发射单操作数mul或imul为使用类型寄存器大小的两倍int64_t a; __int128_t p = (__int128_t)a * b;因此(i)mul很少需要单操作数imul教学
,使用起来更加灵活imul(因为现在现代编译器几乎只将多操作数imul用于有符号和无符号乘法),因此它们会比单操作数更快(i)mul| 归档时间: |
|
| 查看次数: |
19458 次 |
| 最近记录: |