Assembly 如果找到结构成员,访问速度会更快<;从开始算起128字节?

Assembly 如果找到结构成员,访问速度会更快<;从开始算起128字节?,assembly,x86,micro-optimization,Assembly,X86,Micro Optimization,从中,我读到: 如果 相对于结构或类开头的成员较少 大于128,因为偏移量可以表示为8位有符号 号码。如果相对于结构起点的偏移或 类为128字节或更多,则偏移量必须表示为 32位数字(指令集在8位和32位之间没有任何内容 位偏移)。例如: 这里b的偏移量是400。通过a访问b的任何代码 指针或成员函数(如ReadB)需要将偏移量编码为 32位数字。如果a和b交换,则可以使用 编码为8位有符号数字的偏移量,或在 全部的这使得代码更加紧凑,从而可以使用代码缓存 效率更高。因此,建议使用大型阵列和 其

从中,我读到:

如果 相对于结构或类开头的成员较少 大于128,因为偏移量可以表示为8位有符号 号码。如果相对于结构起点的偏移或 类为128字节或更多,则偏移量必须表示为 32位数字(指令集在8位和32位之间没有任何内容 位偏移)。例如:

这里b的偏移量是400。通过a访问b的任何代码 指针或成员函数(如ReadB)需要将偏移量编码为 32位数字。如果a和b交换,则可以使用 编码为8位有符号数字的偏移量,或在 全部的这使得代码更加紧凑,从而可以使用代码缓存 效率更高。因此,建议使用大型阵列和 其他大对象在结构或类声明中排在最后 最常用的数据成员排在第一位。如果不可能 包含前128字节内的所有数据成员,然后放入最大 前128字节中经常使用的成员

我已经试过了,我发现这个测试程序的汇编输出没有什么不同,如图所示:

输出是

push    rbp
mov     rbp, rsp
sub     rsp, 712
mov     DWORD PTR [rbp-416], 32
mov     DWORD PTR [rbp-432], 16
mov     eax, 0
leave
ret
显然,
mov DWORD PTR
用于这两种情况

  • 有人能解释为什么会这样吗
  • 有人能解释一下“指令集在8位和32位偏移量之间没有任何内容”(我是ASM新手)的含义吗?这句话表明我应该在ASM中看到什么

  • 您应该查看asm的
    ReadB
    ,而不是
    main
    ;但由于它们是内联定义的,所以除非您调用它们,否则不会生成asm(然后它将与调用函数的代码混合在一起)。让我们把它们移到一边,这样更容易些

    class S2 {
    public:
        int a[100];
        int b;
        int ReadB();
    };
    
    int S2::ReadB() { return b; }
    
    等等

    此外,仅查看asm代码不会显示指令的大小。您需要查看实际的机器代码字节。在godbolt中检查“Output:compiletobinary”就可以做到这一点;在一台真正的机器上,您可以编译成一个对象文件,并使用
    objdump--discomble
    或显示机器代码的类似反汇编工具进行转储

    有关更新版本,请参阅

    这些函数中的每一个都在
    rdi
    中使用
    this
    指针,并且需要将
    this->b
    移动到
    eax
    。因此,它需要在rdi给定的地址加上相关类中
    b
    的偏移量从内存中加载dword。现在你可以看到:

    • b
      位于
      a
      之后时,对于
      mov-eax,DWORD-PTR[rdi+0x190]

    • b
      在课程开始时,您将获得
      8b07
      (2字节)用于
      mov eax,DWORD PTR[rdi]

    • b
      a
      之前,但在新的
      int
      成员
      other
      之后,您将获得
      8b 47 04
      mov-eax,DWORD-PTR[rdi+0x4]

    此处使用三种不同的地址,它们可以通过三种方式指定要从中加载的地址:

    • 作为寄存器(指令需要两个字节)

    • 作为一个寄存器加上一个有符号8位位移(占用1个额外字节)

    • 作为一个寄存器加上一个有符号的32位位移(额外占用4个字节)

    如果必要的位移为非零但适合8位,则可以使用第二种形式。如果没有,那么您就只能使用第三种形式,使代码增加3个字节。(正如prl所指出的,这并不一定会使它变慢,但它往往会变慢,因为它会占用更宝贵的缓存。)


    “Nothing between”指的是这样一种想法,即您可能希望有一个具有16位位移的表单,该位移足够大,可以容纳位移
    400
    ,但只使用两个额外的字节。但是没有。

    汇编源代码不显示每个指令的大小。要查看差异,请查看显示每条指令的地址和字节的反汇编或汇编列表。您看不到它,因为您的代码直接在堆栈上寻址,相对于帧指针,而不是结构的基。创建一个指向类的指针的函数。还要注意,建议的优化不会直接影响执行速度。它会影响指令大小,而指令大小可能会或不会对执行速度产生次要影响,这取决于许多其他因素。Dword ptr表示操作数的大小。这并不意味着指令是如何编码的,汇编程序会计算出来。请检查
    push    rbp
    mov     rbp, rsp
    sub     rsp, 712
    mov     DWORD PTR [rbp-416], 32
    mov     DWORD PTR [rbp-432], 16
    mov     eax, 0
    leave
    ret
    
    class S2 {
    public:
        int a[100];
        int b;
        int ReadB();
    };
    
    int S2::ReadB() { return b; }