机器级编程
定义
机器级编程(Machine-level Programming)是直接与计算机硬件交互的编程形式,通常使用汇编语言或机器语言。
存在的抽象(重要)
- ISA :用于定义机器级程序的格式和行为(详情见CS61C)
- 虚拟内存 :机器级程序使用的内存地址是虚拟地址
机器级编程常用工具(暂时空缺,在需要的时候查手册吧,未来将会补全)
gcc
objdump
gdb
关于格式的注解
伪指令
伪指令(Pseudo-instructions)是汇编语言中不直接对应于机器语言指令的指令。相反,汇编器(Assembler)会将伪指令转换为一条或多条实际的机器指令。这些伪指令提供了一种更方便和人性化的方式来完成某些任务,使得编写和阅读汇编代码更加容易。以下是一些常见的伪指令及其作用:
- 数据定义伪指令:用于定义常量或变量在内存中的位置和初始值。
.data
:指定数据段的开始。.text
:指定代码段的开始。.byte
,.word
,.long
,.quad
:定义不同大小的数据(8位、16位、32位、64位)。.ascii
,.asciiz
:定义字符或字符串(asciiz
以空字符结尾)。
.data
value: .word 42 ; 定义一个16位的整数,值为42
message: .asciiz Hello, World! ; 定义一个以空字符结尾的字符串
- 控制伪指令:用于控制程序的汇编过程。
.globl
:声明一个全局符号,使其在其他文件中可见。.align
:对齐数据到指定的边界。.equ
,.set
:定义常量。
.globl _start ; 声明_start符号为全局
.align 4 ; 对齐到4字节边界
max_value: .equ 100 ; 定义常量max_value为100
- 分配存储伪指令:用于分配未初始化的内存。
.space
:分配指定字节数的未初始化空间。.skip
:跳过指定字节数(类似于space
)。
buffer: .space 128 ; 分配128字节的未初始化空间
- 宏指令:通过定义宏来简化代码的编写。宏是包含一组指令的代码块,可以像伪指令一样使用。
.macro
和.endm
:定义和结束一个宏。
.macro clear_register reg
xor \reg, \reg ; 将寄存器清零
.endm
clear_register %eax ; 使用宏清零eax寄存器
伪指令的主要目的是提高代码的可读性和可维护性,减少直接操作复杂性。汇编器在处理伪指令时,会将其转化为相应的机器指令或数据布局,以便CPU可以理解和执行。
在C语言中插入汇编代码
在C语言中插入汇编代码通常被称为内联汇编(Inline Assembly)。在GCC编译器中,这通过asm
或__asm__
关键字实现。在微软的Visual C++编译器中,这通过__asm
关键字实现。以下是详细介绍如何在这两种编译器中插入汇编代码的方法。
tips:可以添加内存栅障来防止优化,利用这个方法
int main() {
int a = 10, b = 20, c;
__asm__ (addl %%ebx, %%eax
: =a (c)
: a (a), b (b)
);
printf(Result: %d\n, c);
return 0;
}
#include <stdio.h>
void memory_barrier() {
__asm__ __volatile__( ::: memory);
}
int main() {
int a = 0;
int b = 0;
a = 1;
memory_barrier(); // 确保a的赋值操作完成后再进行b的赋值操作
b = 1;
printf(a = %d, b = %d\n, a, b);
return 0;
}