【汇编】简单的linux汇编语言程序

一、Linux系统汇编语言【汇编】简单的linux汇编语言程序_第1张图片

Linux系统上的汇编语言可以使用不同的语法风格,主要包括Intel语法和AT&T语法。这两种语法有各自的特点和风格区别,尽管它们表示的底层机器指令相同。下面分别对两种语法进行简要说明:

Intel语法

Intel语法是由Intel公司为其处理器编写官方文档时所采用的语法。它广泛用于Windows操作系统和一些跨平台的程序中。特点是相对直观,操作数的顺序是"操作 目的地, 源"。这意味着第一个操作数是将要被赋值的对象,而第二个操作数是赋值的值。例如:

mov eax, 1 ; 将数值1赋给寄存器eax

AT&T语法

AT&T语法由Unix系统V的开发者使用,并且在GNU汇编器(GAS)中被广泛采纳。它在用于x86架构上的Linux系统中非常普遍。与Intel语法相反,它采用的是"操作 源, 目的地"的格式。特点是操作数带有明确的大小标识符,如`%eax`(32位寄存器)和`$1`(立即数)。同样的例子在AT&T语法中为:

movl $1, %eax ; 将数值1赋给寄存器eax

两种语法的主要差异

- 操作数顺序:Intel语法以"目标, 源"的顺序,而AT&T语法则相反,采用"源, 目标"。
- 寄存器前缀:AT&T语法使用`%`作为寄存器前缀,而Intel语法不使用。
- 立即数前缀:AT&T语法使用`$`作为立即数前缀,而Intel语法不使用。
- 大小标识符:AT&T语法对操作数的大小使用后缀,如`b`(字节)、`w`(字)、`l`(长字,32位)。
- 地址表示:AT&T语法使用`段寄存器:偏移量(基址寄存器,索引寄存器,比例因子)`的格式,而Intel语法则不同,不使用冒号而是用括号来区分不同的寄存器角色。
- 指令后缀:AT&T语法的指令通常有后缀来标识操作数类型,而Intel语法通常没有指令后缀。
这些差异使得同一个汇编程序在两种语法中看起来非常不同。但无论采用哪种语法,最终产生的机器码是相同的,只是人类编程者的表达方式不同而已。在进行汇编语言编程时,需要根据所使用的工具和个人偏好来选择适合的语法。 

二、Intel语法示例【汇编】简单的linux汇编语言程序_第2张图片

Linux环境下搭建NASM

1. 安装NASM

在基于Debian的Linux发行版(如Ubuntu)中,可以使用以下命令安装NASM:

   sudo apt update
   sudo apt install nasm

在基于Red Hat的发行版(如Fedora或CentOS)中,使用:

sudo dnf install nasm

或者(较旧的版本使用yum):

 sudo yum install nasm
2. 验证安装

   安装完成后,在终端验证NASM版本确认安装成功:

   nasm -v

编写汇编程序

创建一个名为 hello_world.asm 的文本文件,并将以下汇编代码复制到文件中:

section .data               ; 这是数据段
msg db 'Hello, World!', 0xA ; 'Hello, World!' 字符串和一个换行符
len equ $ - msg             ; 字符串长度

section .text               ; 以下是代码段
global _start               ; _start 是程序入口

_start:
    ; 写入字符串到 stdout
    mov eax, 4              ; '4' 是写系统调用的编号
    mov ebx, 1              ; '1' 是文件描述符 stdout
    mov ecx, msg            ; 将消息的地址移到 'ecx'
    mov edx, len            ; 消息的长度
    int 0x80                ; 调用内核

    ; 退出程序
    mov eax, 1              ; '1' 是退出系统调用的编号
    mov ebx, 0              ; 返回值 0 ,表示无错误
    int 0x80                ; 调用内核

使用汇编器编译代码

编译刚才写的 hello_world.asm。在终端中运行:

nasm -f elf32 hello_world.asm -o hello_world.o

这将生成一个名为 hello_world.o 的目标文件。

 链接目标文件以创建可执行文件

使用链接器创建可执行程序:

ld -m elf_i386 hello_world.o -o hello_world

此命令会创建一个名为 hello_world 的可执行文件。

运行程序

运行程序并看到其输出:

./hello_world

应该会在屏幕上看到 Hello, World! 的信息。

使用调试器

如果想要观察程序在运行时的具体行为,可以使用调试器,例如 gdb。运行以下命令来启动调试器:

gdb ./hello_world

在 gdb 中,可以设置断点,运行程序,逐步执行指令,并且观察寄存器和内存的状态。例如,要运行程序直到其完成,可以在 gdb 提示符下输入 run 命令:

(gdb) run

要退出 gdb,可以使用 quit 命令。

汇编语言依赖于使用的架构和操作系统。不同的汇编器和链接器可能需要不同的指令和参数。上述示例假设使用基于 Intel 语法的 x86 架构,且在 Linux 系统上。如果在其他平台上工作,需要适当调整这些命令。 

三、AT&T语法示例【汇编】简单的linux汇编语言程序_第3张图片

GCC允许在C程序中嵌入汇编代码,或者直接编写一个纯汇编文件并使用GCC进行编译和链接。

下面是一个使用AT&T语法的简单汇编程序示例,该程序在Linux系统上打印"Hello, World!"。这个程序是为x86架构编写的,并且假设正在使用32位系统或已经安装了必要的多架构支持。

首先,创建一个名为hello.s的汇编源文件:

# hello.s  
.section .data  
hello_string:  
    .string "Hello, World!\n"  
  
.section .text  
.global _start  
  
_start:  
    # 写入系统调用  
    movl $4, %eax         # 系统调用号 (sys_write)  
    movl $1, %ebx         # 文件描述符 (stdout)  
    movl $hello_string, %ecx  # 字符串地址  
    movl $14, %edx        # 字符串长度(包括换行符)  
    int $0x80             # 调用内核  
  
    # 退出系统调用  
    movl $1, %eax         # 系统调用号 (sys_exit)  
    xorl %ebx, %ebx       # 退出状态码  
    int $0x80             # 调用内核

然后,使用GCC编译并链接这个程序:

gcc -static -o hello hello.s -nostartfiles -nostdlib

这里的编译选项解释如下:

  • -static:生成静态链接的可执行文件,这样就不需要动态链接器来加载运行时库。
  • -nostartfiles:不链接标准启动文件,这些文件通常包含程序入口点(如_start),因为我们已经在汇编代码中提供了。
  • -nostdlib:不链接标准C库,这样GCC就不会自动包含例如libc这样的库。

编译成功后,就可以运行生成的可执行文件了:

./hello

如果一切正常,它应该在终端上打印出"Hello, World!"。

这个程序没有使用C标准库或任何其他的库函数。它直接通过Linux的系统调用来输出字符串和结束程序。此外,这个程序是针对32位系统的;如果正在使用64位系统,需要对代码进行一些修改,包括使用不同的寄存器和系统调用号。在64位系统上,可能还需要使用-m32选项来告诉GCC生成32位代码(并且确保已经安装了必要的32位开发工具和库)。

你可能感兴趣的:(编程,#,linux,汇编,linux)