在浏览一些具有内联汇编的C代码时,我遇到了.byte(开头有一个Dot)指令。
在检查web上的程序集引用时,我发现它用于在内存中保留一个字节。
但是在代码中,声明之前没有标签。所以我想知道什么是未标记的.byte指令或任何其他数据存储指令的使用。
例如如果我编码.byte 0x0a
,我该如何使用它?
答案 0 :(得分:7)
有几种可能性......这里有一对我可以想到的情侣:
您可以相对于 .byte
指令后出现的标签访问它。例如:
.byte 0x0a
label:
mov (label - 1), %eax
根据程序的最终链接布局,.byte
指令可能会作为代码执行。通常情况下,你也会在这种情况下有一个标签,但是......
有些汇编程序不支持为操作数大小等生成x86指令前缀。在为这些汇编程序编写的代码中,您经常会看到如下内容:
.byte 0x66
mov $12, %eax
使汇编程序发出您想要的代码。
答案 1 :(得分:2)
以下是内联汇编的示例:
#include <stdio.h>
void main() {
int dst;
// .byte 0xb8 0x01 0x00 0x00 0x00 = mov $1, %%eax
asm (".byte 0xb8, 0x01, 0x00, 0x00, 0x00\n\t"
"mov %%eax, %0"
: "=r" (dst)
: : "eax" // tell the compiler we clobber eax
);
printf ("dst value : %d\n", dst);
return;
}
(见compiler asm output and also disassembly of the final binary on the Godbolt compiler explorer。)
您可以将.byte 0xb8, 0x01, 0x00, 0x00, 0x00
替换为mov $1, %%eax
运行结果将是相同的。这表明它可以是一个可以表示某些指令的字节,例如移动或其他指令。
答案 2 :(得分:2)
最小可运行示例
无论你身在何处, .byte
都会吐出字节。无论是否有标签指向该字节都没关系。
如果您恰好位于文本段中,那么该字节可能会像代码一样运行。
Carl提到了它,但是这里有一个完整的例子让它进一步下沉:true
的Linux x86_64实现,其中引入了nop
:
.global _start
_start:
mov $60, %rax
nop
mov $0, %rdi
syscall
生成完全相同的可执行文件:
.global _start
_start:
mov $60, %rax
.byte 0x90
mov $0, %rdi
syscall
因为nop
被编码为字节0x90
。
一个用例:新说明
一个用例是将新指令添加到CPU ISA中,但只有非常优秀的汇编程序版本才支持它。
因此,项目维护人员可以选择直接内联字节,以便在旧的汇编程序中进行编译。
例如,在Linux内核上使用类似的.inst
指令查看此Specter变通方法:https://github.com/torvalds/linux/blob/94710cac0ef4ee177a63b5227664b38c95bbf703/arch/arm/include/asm/barrier.h#L23
#define CSDB ".inst 0xe320f014"
为Spectre添加了一条新指令,内核决定暂时对其进行硬编码。
答案 3 :(得分:0)
.byte是一个指令,它允许你声明一个只有通过检查才知道的常量字节而没有任何上下文。
来自GNU汇编程序指南:
.byte 74, 0112, 092, 0x4A, 0X4a, 'J, '\J # All the same value.