gpt4 book ai didi

assembly - CS :APP example uses idivq with two operands?

转载 作者:行者123 更新时间:2023-12-02 21:58:18 25 4
gpt4 key购买 nike

我正在通过“计算机系统程序员的观点”(第 3 版)一书阅读有关 x86-64(以及一般的汇编)的信息。根据网络上的其他来源,作者声明 idivq只接受一个操作数 - 就像 this一个 claim 。但是,作者在几章之后给出了一个示例,指令为 idivq $9, %rcx .

两个操作数?我起初认为这是一个错误,但从那里开始在书中发生了很多。

此外,应根据寄存器 %rdx 中的数量给出股息。 (高阶 64 位)和 %rax (低阶 64 位)-因此,如果在体系结构中定义了这一点,那么第二个操作数似乎不可能是指定的被除数。

这是一个练习的例子(懒得把它全部写下来 - 所以一张图片是要走的路)。它声称 GCC 发出 idivq $9, %rcx编译一个简短的 C 函数时。

最佳答案

这是一个错误。 只有 imul 有立即和 2 登记表。

mul、div 或 idiv 仍然仅以单操作数形式存在 与 8086 一起引入,使用 RDX:RAX 作为输出的隐式双宽操作数(和除法的输入)。

或 EDX:EAX、DX:AX 或 AH:AL,当然取决于操作数大小。查阅 ISA 引用资料,如英特尔手册,而不是本书! https://www.felixcloutier.com/x86/idiv

另见 When and why do we sign extend and use cdq with mul/div?Why should EDX be 0 before using the DIV instruction?

x86-64 唯一的硬件划分指令是 idivdiv .移除了 64 位模式 aam , 以立即数进行 8 位除法。 ( Dividing in Assembler x86Displaying Time in Assembly 有一个在 16 位模式下使用 aam 的例子)。

当然是用常数除法 idivdiv (和 aam )非常低效。除非您针对代码大小而不是性能进行优化,否则请使用 2 的幂的移位,否则使用乘法逆运算。

CS:APP 3e全局版在实践问题中显然有多个像这样的严重x86-64指令集错误,声称GCC发出不可能的指令 .不仅仅是拼写错误或细微的错误,还有误导性的废话,这对于熟悉 x86-64 指令集的人来说显然是错误的。这不仅仅是一个语法错误,它试图使用不可编码的指令(没有语法可以表达它们,除了扩展为多个指令的宏。使用宏将 idivq 定义为伪指令将是很奇怪)。

例如I correctly guessed missing part of a function, but gcc generated assembly code doesn't match the answer是另一个提示 (%rbx, %rdi, %rsi)(%rsi, %rsi, 9)是有效的寻址模式!比例因子实际上是 2 位移位计数,因此这些完全是垃圾,表明作者严重缺乏他们正在教授的 ISA 知识,而不是打字错误。

他们的代码不会用任何 AT&T 语法汇编器进行汇编。

还有 What does this x86-64 addq instruction mean, which only have one operand? (From CSAPP book 3rd Edition)是另一个例子,他们有一个荒谬的 addq %eax而不是 inc %rdx ,以及 mov 中不匹配的操作数大小店铺。

似乎他们只是在编造东西并声称它是由 GCC 发出的 . IDK 如果他们从真正的 GCC 输出开始并将其编辑为他们认为更好的示例,或者实际上从头开始手写而不进行测试。

GCC 的实际输出将使用乘法与魔法常数(定点乘法逆)除以 9(即使在 -O0 处,但这显然不是 Debug模式代码。他们本可以使用 -Os )。

想必他们不想谈Why does GCC use multiplication by a strange number in implementing integer division?并用他们编写的指令替换了该代码块。从上下文中,您可能可以弄清楚他们期望输出的去向;也许他们的意思是 rcx /= 9 .

这些错误来自全局版的3rd方练习题

来自出版商的网站 ( https://csapp.cs.cmu.edu/3e/errata.html )

Note on the Global Edition: Unfortunately, the publisher arranged for the generation of a different set of practice and homework problems in the global edition. The person doing this didn't do a very good job, and so these problems and their solutions have many errors. We have not created an errata for this edition.



所以CS:APP 3e大概是一本不错的教材,只要拿到北美版,或者忽略练习/作业问题。这解释了教科书的声誉和广泛使用与严重和明显(对熟悉 x86-64 asm 的人而言)这样的错误之间的巨大脱节,这些错误超出了草率进入不了解语言领域的范围。

如何假设 idiv reg, regidiv $imm, reg将被设计

Also, the dividend should be given from the quantity in registers %rdx (high-order 64 bits) and %rax (low-order 64 bits) - so if this is defined in the architecture then it does not seem possible that the second operand could be a specified dividend.



如果英特尔或 AMD 为 div 引入了一种新的方便形式或 idiv , 他们会设计它使用单宽度红利,因为编译器总是这样使用它。

大多数语言都像 C 语言一样,将 + - */的两个操作数隐式提升为相同的类型并产生该宽度的结果。当然,如果已知输入很窄,则可以对其进行优化。 (例如,使用一个 imul r32 来实现 a * (int64_t)b )。

但是 dividiv如果商溢出则错误,因此使用单个 32 位不安全 idiv编译时 int32_t q = (int64_t)a / (int32_t)b .

编译器总是使用 xor edx,edx在 DIV 或 cdq 之前或 cqo在 IDIV 实际做 n/n => n 位除法之前。

使用不只是零或符号扩展的红利的真正全角除法只能通过内部函数或 asm 手动完成(因为 gcc/clang 和其他编译器不知道优化何时是安全的),或者在 gcc 中帮助函数,例如32 位代码中的 64 位/64 位除法。 (或 64 位代码中的 128 位除法)。

因此,最有用的是 div/idiv,它也避免了设置 RDX 的额外指令,并最大限度地减少了隐式寄存器操作数的数量。 (就像 imul r32, r/m32 and imul r32, r/m32, imm 做的那样:在没有隐式寄存器的情况下使非扩展乘法的常见情况更方便。这是英特尔的语法,如手册,目的地优先)

最简单的方法是执行 dst /= src 的 2 操作数指令。 .或者可能用商和余数替换两个操作数。对 3 个操作数使用 VEX 编码,例如 BMI1 andn ,你可能有 idivx remainder_dst, dividend, divisor .第二个操作数也是商的输出。或者,您可以将余数写入 RDX,并使用商的非破坏性目标。

或者更有可能针对只需要商的简单情况进行优化, idivx quot, dividend, divisor并且不要将剩余部分存储在任何地方。您可以随时使用常规 idiv当你想要商时。

BMI2 mulx 使用隐式 rdx输入操作数,因为它的目的是允许多个带进位加法链用于扩展精度乘法。所以它仍然必须产生 2 个输出。但是这种假设的新形式 idiv将存在以节省 idiv 的正常使用周围的代码大小和 uops没有扩大。所以 386 imul reg, reg/mem是比较点,不是BMI2 mulx .

IDK 如果引入 idivx 的直接形式有意义同样;您只会出于代码大小的原因使用它。乘法逆运算更有效地除以常数,因此这种指令在现实世界中的用例很少。

关于assembly - CS :APP example uses idivq with two operands?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57998998/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com