当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?
在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汇编的怪癖).
简介:我正在查看汇编代码来指导我的优化,并在将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,因为寄存器溢出会增加代码的缓存占用空间.
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,dil和al来代替.也许有人会说,此功能不会让任何性能上的差异,但有一个在之间的可执行文件的大小有很大的区别mov $1, %rax => b801000000,并mov $1, %al => b001当我们谈论数千寄存器的程序访问.如果软件的优雅部分不仅体积小,它确实会对性能产生影响.
有人可以解释为什么"海湾合作委员会决定"它无所谓?
我注意到一些非常奇怪的东西.说我已经定义了以下结构
typedef struct
{
uint32_t a;
uint16_t b;
uint32_t c;
} foo;
Run Code Online (Sandbox Code Playgroud)
这个结构包含在我从网络接收的大缓冲区中.
以下代码适用于x86,但我SIGBUS在ARM上收到.
extern void * buffer;
foo my_foo;
my_foo = (( foo * ) buffer)[0];
Run Code Online (Sandbox Code Playgroud)
用memcpy替换解除引用的指针解决了这个问题.
在ARM中搜索SIGBUS时,我发现这与内存对齐somwhow有关.
有人可以解释发生了什么吗?
我正在从《计算机系统:程序员的视角》学习 x86-64 汇编,并且遇到了一个练习,要求将一行 C 代码转换为(两个)等效的汇编指令。该代码是关于使用指针将一种类型的变量复制到另一种类型的变量。
指针变量声明如下:
src_t *sp; //src_t and dest_t are typedefs
dest_t *dp;
Run Code Online (Sandbox Code Playgroud)
需要翻译的C代码是:
*dp = (dest_t)*sp;
Run Code Online (Sandbox Code Playgroud)
假设指针sp和分别dp存储在寄存器%rdi和%rsi中,并且我们应该设置%rax(例如 、%eax或%ax)的“适当部分”%al来进行中间数据复制(因为 x86-64 不允许源和目标同时复制)是内存引用)。
现在,当src_tisunsigned char和dest_tis 时long,我为其编写了以下汇编代码:
movzbq (%rdi), %rax //move a byte into %rax with zero extension
movq %rax, (%rsi) //move 8 bytes of 'long' data
Run Code Online (Sandbox Code Playgroud)
但这本书以及Godboltgcc (与 一起使用-O3)都说它应该是
movzbl (%rdi), %eax …Run Code Online (Sandbox Code Playgroud)