x86-64汇编问题请教

发布于 2022-09-19 13:41:38 字数 938 浏览 14 评论 0

这里有篇文档:

http://www.x86-64.org/documentation/assembly.html

文档中有一段:

Immediate values inside instructions remain 32 bits and their value is sign extended to 64 bits before calculation. This means that:

  addq $1, %rax                         # Valid instruction
  addq $0x7fffffff, %rax         # As this
  addq $0xffffffffffffffff, %rax # as this one
  addq $0xffffffff, %rax         # Invalid instruction
  addl $0xffffffff, %eax         # Valid instruction

红色的这句没看懂, 为什么立即数符号扩展到64位, 对32位的-1来说就不行?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

缘字诀 2022-09-26 13:41:38

有这事?!

—━☆沉默づ 2022-09-26 13:41:38

原帖由 albcamus 于 2008-7-16 15:08 发表
这里有篇文档:

http://www.x86-64.org/documentation/assembly.html

文档中有一段:

红色的这句没看懂, 为什么立即数符号扩展到64位, 对32位的-1来说就不行?

奇怪哦,intel的手册上对这段的论述,没有提到有-1非法的情况

2.2.1.5   Immediates
In 64-bit mode, the typical size of immediate operands remains 32 bits. When the
operand size is 64 bits, the processor sign-extends all immediates to 64 bits prior to
their use.
Support for 64-bit immediate operands is accomplished by expanding the semantics
of the existing move (MOV reg, imm16/32) instructions. These instructions (opcodes
B8H ¨C BFH) move 16-bits or 32-bits of immediate data (depending on the effective
operand size) into a GPR. When the effective operand size is 64 bits, these instruc-
tions can be used to load an immediate into a GPR. A REX prefix is needed to override
the 32-bit default operand size to a 64-bit operand size.
For example:
48 B8 8877665544332211 MOV RAX,1122334455667788H

清欢 2022-09-26 13:41:38

原帖由 zx_wing 于 2008-7-16 15:20 发表

奇怪哦,intel的手册上对这段的论述,没有提到有-1非法的情况

谢谢两位关注。

感觉好像不是-1非法, 而是 > 0x7fffffff的立即数都非法!  没明白为什么会这样。。。

故事未完 2022-09-26 13:41:38
[ ~]$ cat aa.c
/* filename :aa.c */
#include <stdio.h>

int main(void)
{
        unsigned long long tmp = 2;

        /* 下面这行改成asm volatile("addq $0x7fffffff, %0" 就可以 */
        asm volatile("addq $0x80000000, %0"
                     : "=a" (tmp)
                     : "0" (tmp)
                    );

        printf("tmp is %llu\n", tmp);

        return 0;
}
[~]$ gcc -m64 aa.c
/var/tmp//ccXZa4Ns.s: Assembler messages:

/var/tmp//ccXZa4Ns.s:19: Error: suffix or operands invalid for `add'

记忆で 2022-09-26 13:41:38

这好像是个基本功问题? 感觉很诡异, 一定是关于汇编, 我们有某个很初级的地方没弄明白。

水染的天色ゝ 2022-09-26 13:41:38

刚好是32位的界限。不懂

秉烛思 2022-09-26 13:41:38

这个问题应该和REX前缀没关系。

        
    只有在64bit模式下,REX才是有意义的。 AMD x86-64的文档是这么说REX的:
        
        -> 即使是在64bit模式下,operand size仍然默认为32位;

        -> 指令想访问64位的GPR,或者被x86-64扩展了的XMM寄存器,就需要REX前缀;

        -> 只有一部分指令是例外:对这些指令来说,默认情况下operand size就是64bit。
           因此,这些指令不需要REX前缀

/*{{{*/默认的operand size == 64bit,从而不需要REX前缀的指令:
    CALL (Near)     POP reg/mem
    ENTER           POP reg
    Jcc             POP FS
    JrCXZ           POP GS
    JMP (Near)      POPFQ
    LEAVE           PUSH imm8
    LGDT            PUSH imm32
    LIDT            PUSH reg/mem
    LLDT            PUSH reg
    LOOP            PUSH FS
    LOOPcc          PUSH GS
    LTR             PUSHFQ
    MOV CR(n)       RET (Near)
    MOV DR(n)
/*}}}*/
   
    所谓REX prefix,其实是指令码(opcode)的最低一个字节(8bit),合法值是0x41 - 0x4f。
        

    注意,把REX.W设置为1,就指定了64位的operand size。

Table: REX Prefix-Byte Fields

じее 2022-09-26 13:41:38

mik版主写过a64汇编器, 是不是 对Unix来说, 只有as作者才需要关注REX?

请帮我爱他 2022-09-26 13:41:38

原帖由 albcamus 于 2008-7-16 17:22 发表
mik版主写过a64汇编器, 是不是 对Unix来说, 只有as作者才需要关注REX?

偶最善此道了。

你提到的问题并不复杂。 实际上只是汇编语言层面的语法而已。

1、从本质上讲与你所说的 -1 完全无关,也没有什么 0x7fffffff 的制约。

2、出现 addq $0xffffffff, %rax    错误的原因完全是语法问题,或者说是 gas 这个汇编器的语法限制,当然在 masm 的语法也有这方面的限制。
   从 amd64 的指令本质来说:add rax, 0FFFFFFFF 是完全正确的。
   反而 add rax, 0FFFFFFFFFFFFFFFF 这是错误的。因为,x86_64 指令要求的立即数除了mov,push 指令外的其它指令,是不允许有64位立即数的。
   然而,从汇编语法上来讲:x86 & x64 的指令格式绝大部分要求:源操作数与目的操作数的大小要一致汇编器在进行翻译为机器码时,就会遵从指令的本质。
   

3、所以,基于第2条的论述:
     addq $0xffffffffffffffff, %rax      这条指令译为机器码是:
     49 05 FF FF FF FF       // 共 6 个字节,而不是 10 个字节

同样: 若是: 49 05 FF FF FF FF          // 会被 objdump 之类的程序显示为: addq $0xFFFFFFFFFFFFFFFF, %rax
                                                          // 而不会显示为: addq $0xFFFFFFFF, %rax

     总结: 这可以说是语法,或者是显示上的问题,而不论是 AMD 或 Intel 的官方文档上说的是:指令的本质问题。
    所以,若遇到另一个汇编编译器,对 add rax, 0xFFFFFFFF  这条指令判断是正确的话,也不要觉得奇怪,这是它的语法上可以通过
    我自己写的 a64 是按本质来定语法的

4、另外,扯一下, add 与 mov 这两类指令的 64 位立即数编码的区别:
   addq $0xffffffffffffffff, %rax          // 基上所述是: 6 个字节
   movq $0xffffffffffffffff, %rax         // 则是实打实的: 10 个字节。 mov 与 push 指令是唯一可接受64位立即数的两条指令

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文