汇编语言学习(2)

更好的阅读体验,请点击 YinKai’s Blog。

基本语法

汇编程序可以分为三个部分:

  • 数据部分(data section)
  • 未初始化数据部分(bss section)
  • 文本部分(text section)
data 部分

​ 数据部分通常用于存储程序中需要初始化的数据。这可以包括常量、变量和其他静态数据。这个部分的数据在程序运行之前被初始化,并且在整个程序的执行过程中保持不变。

​ 声明数据部分的语法如下:

section .data
bss 部分

​ 未初始化数据部分用于存储程序中未初始化的全局和静态变量。与数据部分不同,bss 部分的变量在程序加载时不会被初始化,而是在运行时由系统初始化为零或空值。这样可以节省可执行文件的大小,因为在文件中只需要记录这些变量的名称和大小,而不需要存储它们的实际值。

​ 声明 bss 部分的语法如下:

section .bss
text 部分

​ 文本部分包含程序的实际代码。这是程序的主要执行部分,包括机器指令和指令的地址。在这个部分,汇编程序将源代码翻译成机器可执行的指令,使得计算机能够按照特定的算法执行相应的操作。

​ 声明 文本部分的语法如下:

section .text
注释

​ 汇编语言中的注释以分号;开头。注释可以独立一行存在,也可以与指令在同一行。例如:

; This is a line of comments
add eax, ebx ; adds ebx to eax
汇编语言语句

​ 汇编语言程序由三种类型的语句组成:

  • 可执行指令:告诉处理器要执行的操作,每条指令包括操作码和操作数
  • **汇编器指令或伪操作:**用于影响汇编过程的方面,它们不会生成机器语言指令
  • **宏:**一种文本替换机制
汇编语言语句的语法

​ 汇编语言语句每行输入一个语句,每个语句都遵循以下格式:

[label]    mnemonic    [operands]    [;comment]

​ 方括号中的字段是可选的。

​ 基本指令由两部分组成,第一部分是哟啊执行的指令名词(或助记符),第二部分是命令的操作数或参数。

​ 以下是一些典型汇编语言语句的示例:

  1. MOV指令(数据传送):

    MOV AX, 42       ; 将值42存储到寄存器AX中
    MOV BX, AX       ; 将寄存器AX的值传送到寄存器BX中
    
  2. ADD和SUB指令(加法和减法):

    ADD AX, BX       ; 将寄存器AX和BX中的值相加,并将结果存储在AX中
    SUB CX, 10       ; 从寄存器CX中减去值10,并将结果存储在CX中
    
  3. CMP和JMP指令(比较和跳转):

    CMP AX, BX       ; 比较寄存器AX和BX的值
    JE  label        ; 如果相等,则跳转到标签label处
    JG  another_label ; 如果大于,则跳转到另一个标签another_label处
    JL  target_label         ; 如果小于,跳转到目标标签
    
  4. INC和DEC指令(递增和递减):

    INC SI           ; 将寄存器SI中的值递增1
    DEC CX           ; 将寄存器CX中的值递减1
    
  5. LOOP指令(循环):

    MOV CX, 5        ; 设置循环计数器CX的初始值为5
    loop_start:      ; 循环开始标签
       ; 循环体代码
       DEC CX        ; 循环计数器递减1 
       JNZ loop_start; 如果计数器不为零,则跳转到循环开始标签
    
汇编中的 Hello World 程序
section .data
    msg db 'Hello, world!', 0xa  ; 要打印的字符串,0xa 是换行符
    len equ $ - msg     ; 字符串的长度

section .text
    global _start     ; 必须为链接器(ld)声明的全局入口点
    
_start:             ; 告诉链接器入口点
    ; write message to stdout
    mov eax, 4       ; 系统调用号(sys_write)
    mov ebx, 1       ; 文件描述符(标准输出)
    mov ecx, msg     ; 要写入的消息
    mov edx, len     ; 消息的长度
    int 0x80         ; 调用内核
    
    ; exit the program
    mov eax, 1       ; 系统调用号(sys_exit)
    xor ebx, ebx     ; 返回码为0
    int 0x80         ; 调用内核

上面的代码被编译并执行后,会输出如下内容:

Hello, world!
在 NASM 中编译和链接汇编程序

​ 为了能让上面的程序运行起来,我们需要按下面的步骤编译和链接上述程序:

  1. 使用文本编译器输入上述代码并将其保存为 hello.asm,后续的操作都在该目录下进行
  2. 输入 nasm -f elf hello.asm 编译汇编程序
    • -f elf:这是 NASM 的一个选项,用于指定生成的目标文件的格式。在这里,elf 表示目标文件将采用 ELF(Executable and Linkable Format)格式。
    • ELF 是一种通用的二进制文件格式,用于可执行文件、目标文件和共享库。
  3. 如果程序没有问题,就会程序名为 hello.o 的程序目标文件
  4. 输入 ld -m elf_i386 -s -o hello hello.o 命令,链接目标文件并创建名为 hello 的可执行文件
    • ld: 这是链接器的命令。链接器的作用是将多个目标文件链接在一起,解析符号引用,生成最终的可执行文件。在执行该命令时,链接器会将系统库和其他必要运行时库链接到目标文件 hello.o 中。我们的代码中由于程序只是在标准输出上打印一条消息,因此系统库中的一些 I/O 相关的函数可能被链接进来,以便程序能够正确地执行。
    • -m elf_i386: 这个选项告诉链接器使用 ELF (Executable and Linkable Format) 文件格式,并且生成 32 位 x86 架构的可执行文件。elf_i386 表示生成的可执行文件是面向 32 位 x86 架构的 ELF 文件。
    • -s: 这个选项用于剥离(strip)可执行文件中的符号表信息。符号表包含了程序中定义的各种符号(如变量、函数名等)的信息。在生产环境中,剥离符号表可以减小可执行文件的大小,但同时也会使得可执行文件不易调试。
    • -o hello: 这个选项指定生成的可执行文件的输出名称为 hello-o 是指定输出文件的选项,后面跟着输出文件的名称。
    • hello.o: 这是输入的目标文件,它是由 NASM 编译器生成的,包含了汇编代码的机器代码。
  5. 最后通过 ./hello 执行程序

你可能感兴趣的:(汇编,汇编,nasm)