相关疑难解决方法(0)

什么是严格别名规则?

当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?

c strict-aliasing undefined-behavior type-punning

778
推荐指数
10
解决办法
19万
查看次数

为什么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万
查看次数

将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
查看次数

Linux中的结构分配在ARM中失败但在x86中成功

我注意到一些非常奇怪的东西.说我已经定义了以下结构

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有关.

有人可以解释发生了什么吗?

c linux arm memory-alignment sigbus

3
推荐指数
1
解决办法
1556
查看次数

如果我们只对 64 位寄存器的低 4 字节进行 mov 操作,那么它的高 4 字节是否设置为零

我正在从《计算机系统:程序员的视角》学习 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 chardest_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)

c assembly gcc x86-64

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