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

一、Linux系统汇编语言

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

Intel语法

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

cpp 复制代码
mov eax, 1 ; 将数值1赋给寄存器eax

AT&T语法

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

cpp 复制代码
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环境下搭建NASM

1. 安装NASM

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

bash 复制代码
   sudo apt update
   sudo apt install nasm

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

bash 复制代码
sudo dnf install nasm

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

bash 复制代码
 sudo yum install nasm
2. 验证安装

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

bash 复制代码
   nasm -v

编写汇编程序

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

cpp 复制代码
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。在终端中运行:

bash 复制代码
nasm -f elf32 hello_world.asm -o hello_world.o

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

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

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

bash 复制代码
ld -m elf_i386 hello_world.o -o hello_world

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

运行程序

运行程序并看到其输出:

bash 复制代码
./hello_world

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

使用调试器

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

bash 复制代码
gdb ./hello_world

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

bash 复制代码
(gdb) run

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

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

三、AT&T语法示例

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

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

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

cpp 复制代码
# 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编译并链接这个程序:

bash 复制代码
gcc -static -o hello hello.s -nostartfiles -nostdlib

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

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

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

bash 复制代码
./hello

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

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

相关推荐
HLC++12 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室13 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy15 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕16 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫17 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生18 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1119 小时前
linux基础IO
linux·运维·服务器
BelongPanda21 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯21 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_7779983421 小时前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器