如何仅使用 64 位寄存器在 64 位寄存器中存储 1 个字节值?

Posted

技术标签:

【中文标题】如何仅使用 64 位寄存器在 64 位寄存器中存储 1 个字节值?【英文标题】:How can I store 1byte value in 64bit register only using 64bit registers? 【发布时间】:2019-04-21 01:20:18 【问题描述】:

我只需要使用 %rax、%rbx、%rcx、%rdx、%rsi 和 %rdi(还有 %rsp 和 %rbp)编写像素化汇编代码

所以我首先用 C 编写代码,并将任何其他寄存器更改为 64 位寄存器,但在下面我更改寄存器时,它提供了分段默认值

C 代码:

*temp = b;
*(temp + 1) = g;  
*(temp + 2) = r;

gcc 的汇编代码:

movq    -48(%rbp), %rax  
movl    %eax, %edx
movq    -16(%rbp), %rax  
movb    %dl, (%rax)      
movq    -16(%rbp), %rax  
addq    $1, %rax
movq    -56(%rbp), %rdx  
movb    %dl, (%rax)
movq    -16(%rbp), %rax
addq    $2, %rax
movq    -64(%rbp), %rdx  
movb    %dl, (%rax)

将 %dl 更改为 %rdx:

movq    -16(%rbp), %rax
movq    -48(%rbp), %rdx
movzbq  (%rdx), %rbx
movq    %rbx, (%rax)
movq    -16(%rbp), %rax
addq    $1, %rax
movq    -56(%rbp), %rdx
movzbq  (%rdx), %rbx
movq    %rbx, (%rax)
movq    -16(%rbp), %rax
addq    $2, %rax
movq    -64(%rbp), %rdx
movzbq  (%rdx), %rbx
movq    %rbx, (%rax)

【问题讨论】:

你为什么要这样做? 鼓励打开编译器优化,顺便说一下,汇编输出会更短。 不清楚您要做什么以及为什么。无论如何,如果您只允许使用 64 位存储,如果您只想更新 3 个字节(然后您应该确保所有 8 个字节都可以访问),您将需要一个 read-modify-write。 %dl%rdx 的低字节。您确定您的教授不只是告诉您避免使用 RBX(在 x86-64 System V 调用约定中保留调用)和 R8..R15? 好的,那么您所做的任何字节操作都必须使用 AND 掩码、移位和 OR。或者使用movzbq 从内存中加载。但是你不能做狭窄的商店。 (您可以读取/修改/写入一个 qword 并合并到一个新字节中,但这非常慢。如果您有多个相邻的字节存储要做,请先将它们合并到一个寄存器中并进行一个存储。) 【参考方案1】:

我认为你想做这样的事情:

 t = r & 0xff;
 u = *temp & ~ 0xfful;
 *temp = u | t;
 t = (g & 0xff) << 8;
 u = *temp & ~ 0xff00ul;
 *temp = u | t;
 t  = (b & 0xff) << 16; 
 u = *temp & ~0xff00000ull;
 *temp = u | t;

您应该只能使用 64 位 reg 来编写它。您还应该能够找到一大堆方法来使这种方式比这更小。

【讨论】:

以上是关于如何仅使用 64 位寄存器在 64 位寄存器中存储 1 个字节值?的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地将 zmm 寄存器的低 64 位保存到内存中?

汇编 IA-32:如何将 64 位有符号数除以奇数(存储在 2 个寄存器中)

如何将两个打包的 64 位四字加载到 128 位 xmm 寄存器中

存储介于-64(十六进制)和128(十六进制)之间的值所需的最小寄存器长度?

aarch64 上未对齐 SIMD 加载/存储的性能

ARM NEON:如何对整个 64 位 d 寄存器进行位移?