你在64位英特尔CPU中执行`idiv`之前是否将有符号整数转换为十六进制?

huangapple go评论67阅读模式
英文:

Do you convert signed integers to hex before doing an `idiv` in 64-bit Intel CPUs?

问题

假设你想使用gas将-198077031546722079779除以23。由于这个被除数比%rax大,你该如何放入%rdx:%rax中?我阅读的所有关于汇编的书都避免用例子说明idiv,所以我很困惑。

英文:

Suppose you want to divide -198077031546722079779 by 23 using gas. As this dividend is larger than %rax, how do you put it in %rdx:%rax? All the books I read on assembly avoid illustrating idiv with examples, so I am lost.

答案1

得分: 6

将高位放入 rdx 寄存器,低位放入 rax 寄存器,如您可能已经知道的。

如果您尝试在程序中将该数字用作常数,那么是的,十六进制是一种将其拆分的可能方式。我使用 calc 进行了转换,添加了 2^128 以将其表示为无符号二进制补码数,然后使用 printf("%x") 将其以十六进制打印出来。结果是 0xfffffffffffffff543210543edc9abdd。因此,我们可以这样做:

movq $0xfffffffffffffff5, %rdx
movq $0x43210543edc9abdd, %rax

如果您希望让 gas 为您执行算术运算,那将是很好的。它支持任意精度常数(“bignums”),但不幸的是不允许您在立即数中使用它们。它也不能执行任何与它们相关的算术运算,正如下面的评论所述。

然而,它支持将 128 位整数数据组装到内存中的 .octa 指令。因此,您可以这样做:

.section .rodata
number:
.octa -198077031546722079779
# ...
movq number(%rip), %rax # x86 是小端序,最不重要的 qword 存储在较低的地址
movq (number+8)(%rip), %rdx
# ...

请注意,我们使用了 RIP 相对寻址。如果您在不适当的情况下使用它,只需 movq number, %rax ; movq number+8, %rdx

如果您在运行时接收数字作为输入,那么您将需要实现一个将十进制转换为二进制的转换程序(类似于 strtol),但它需要使用 128 位算术。因此,加法将需要一个 add/adc 对,乘法将需要多个乘法指令,以“手写”方式进行等等。

英文:

You put the high bits into rdx and the low bits into rax, as you probably know.

If you're trying to use the number as a constant in your program, then yes, hex is one possible way to split it up. I converted it using calc, adding 2^128 to express it as an unsigned two's complement number, then using printf("%x") to print it as hex. The result is 0xfffffffffffffff543210543edc9abdd. So we could do

movq $0xfffffffffffffff5, %rdx
movq $0x43210543edc9abdd, %rax

It would be nice if you could have gas do the arithmetic for you. It does support arbitrary-precision constants ("bignums") but unfortunately does not let you use them in immediates. Nor can it do any arithmetic with them, as Jester discovered (per comment below).

However, it does support assembling 128-bit integer data into memory with the .octa directive. So you could do

        .section .rodata
number:
        .octa -198077031546722079779
# ...
movq number(%rip), %rax # x86 is little endian, least significant qword is at lower address
movq (number+8)(%rip), %rdx
# ...

Note we are using RIP-relative addressing. If you're in a situation where that isn't appropriate, then just movq number, %rax ; movq number+8, %rdx.

If you are receiving the number as input at runtime, then you'll need to implement a decimal-to-binary conversion routine (like strtol) but which uses 128-bit arithmetic. So additions will need an add/adc pair, multiplication will need several multiply instructions "longhand" style, etc.

huangapple
  • 本文由 发表于 2023年7月14日 06:43:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76683690.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定