相关疑难解决方法(0)

为什么32位寄存器上的x86-64指令归零整个64位寄存器的上半部分?

x86-64 Tour of Intel Manuals中,我读到了

也许最令人惊讶的事实是,诸如MOV EAX, EBX自动将指令的高32位归零的指令RAX.

同一来源引用的英特尔文档(3.4.1.1 64位手动基本架构中的通用寄存器)告诉我们:

  • 64位操作数在目标通用寄存器中生成64位结果.
  • 32位操作数生成32位结果,在目标通用寄存器中零扩展为64位结果.
  • 8位和16位操作数生成8位或16位结果.目标通用寄存器的高56位或48位(分别)不会被操作修改.如果8位或16位操作的结果用于64位地址计算,则将寄存器显式符号扩展为完整的64位.

在x86-32和x86-64汇编中,16位指令如

mov ax, bx
Run Code Online (Sandbox Code Playgroud)

不要表现出这种"奇怪"的行为,即eax的上层词被归零.

因此:引入这种行为的原因是什么?乍一看似乎不合逻辑(但原因可能是我习惯了x86-32汇编的怪癖).

x86 assembly x86-64 cpu-registers zero-extension

97
推荐指数
3
解决办法
2万
查看次数

现代x86硬件可以不将单个字节存储到内存中吗?

说到C++的并发内存模型,Stroustrup的C++编程语言,第4版,第1节.41.2.1,说:

...(像大多数现代硬件一样)机器无法加载或存储任何小于单词的东西.

但是,我的x86处理器,几年前,可以存储小于一个字的对象.例如:

#include <iostream>
int main()
{
    char a =  5;
    char b = 25;
    a = b;
    std::cout << int(a) << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果没有优化,GCC将其编译为:

        [...]
        movb    $5, -1(%rbp)   # a =  5, one byte
        movb    $25, -2(%rbp)  # b = 25, one byte
        movzbl  -2(%rbp), %eax # load b, one byte, not extending the sign
        movb    %al, -1(%rbp)  # a =  b, one byte
        [...]
Run Code Online (Sandbox Code Playgroud)

评论是由我提出的,但是汇编是由GCC提出的.当然,它运行良好.

显然,我不明白Stroustrup在谈到硬件可以加载和存储任何小于一个单词的内容时所说的内容.据我所知,我的计划什么也不做,但加载和存储对象小于一个字的.

C++对零成本,硬件友好的抽象的彻底关注使C++与其他易于掌握的编程语言区别开来.因此,如果Stroustrup在公交车上有一个有趣的信号心理模型,或者有其他类似的东西,那么我想了解Stroustrup的模型.

什么 Stroustrup谈论,拜托?

更长时间的背景声明 …

c++ concurrency x86 assembly memory-model

25
推荐指数
2
解决办法
1869
查看次数

将32位偏移量添加到x86-64 ABI的指针时是否需要符号或零扩展?

简介:我正在查看汇编代码来指导我的优化,并在将int32添加到指针时看到许多符号或零扩展.

void Test(int *out, int offset)
{
    out[offset] = 1;
}
-------------------------------------
movslq  %esi, %rsi
movl    $1, (%rdi,%rsi,4)
ret
Run Code Online (Sandbox Code Playgroud)

起初,我认为我的编译器在添加32位到64位整数时遇到了挑战,但我已经用Intel ICC 11,ICC 14和GCC 5.3证实了这种行为.

这个帖子证实了我的发现,但不清楚是否需要符号或零扩展.仅当尚未设置高32位时,才需要此符号/零扩展.但x86-64 ABI难道不够聪明吗?

我有点不愿意将所有指针偏移更改为ssize_t,因为寄存器溢出会增加代码的缓存占用空间.

assembly x86-64 abi compiler-optimization sign-extension

16
推荐指数
1
解决办法
2591
查看次数

为什么GCC不使用部分寄存器?

write(1,"hi",3)在linux上反汇编,gcc -s -nostdlib -nostartfiles -O3结果如下:

ba03000000     mov edx, 3 ; thanks for the correction jester!
bf01000000     mov edi, 1
31c0           xor eax, eax
e9d8ffffff     jmp loc.imp.write
Run Code Online (Sandbox Code Playgroud)

我不是到编译器的开发,但由于移动到这些寄存器的每一个值是恒定的和已知的编译时间,我很好奇,为什么不GCC使用dl,dilal来代替.也许有人会说,此功能不会让任何性能上的差异,但有一个在之间的可执行文件的大小有很大的区别mov $1, %rax => b801000000,并mov $1, %al => b001当我们谈论数千寄存器的程序访问.如果软件的优雅部分不仅体积小,它确实会对性能产生影响.

有人可以解释为什么"海湾合作委员会决定"它无所谓?

x86 assembly gcc x86-64

13
推荐指数
2
解决办法
1655
查看次数

现代x86实现可以从多个先前的商店中存储转发吗?

如果负载与两个早期存储重叠(并且负载未完全包含在最早的存储中),现代Intel或AMD x86实现是否可以从两个存储转发以满足负载?

例如,请考虑以下顺序:

mov [rdx + 0], eax
mov [rdx + 2], eax
mov ax, [rdx + 1]
Run Code Online (Sandbox Code Playgroud)

最后的2字节加载从前一个存储区获取其第二个字节,但是它之前的存储区的第一个字节.这个负载可以存储转发,还是需要等到两个先前的存储都提交给L1?

请注意,通过存储转发,我包括任何可以满足仍然存储在缓冲区中的存储的读取的机制,而不是等待它们提交到L1,即使它是一个比最好的情况"转发"更慢的路径.单店"案例.

optimization performance x86 assembly micro-optimization

9
推荐指数
2
解决办法
688
查看次数