机器级编程

定义

机器级编程(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;
}