2025年3月13日 星期四 甲辰(龙)年 月十二 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > 汇编

x86汇编入门

时间:12-11来源:作者:点击数:16

Intel® 64 and IA-32 Architectures Software Developer’s Manual 文档官方地址:

https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf

很好的入门文档:https://www.cdsy.xyz/computer/programme/masm/241210/cd64993.html

汇编语言由三部分组成:

  • 汇编指令:跟机器指令一一对应,实际就算一个个的助记符。有 AT&T 和 INTEL 两种语法
  • 伪指令:给编译器看,用于指示编译器该如何做。不同编译器的语法不同,有 NASM、GNU as 和 MASM 三种常用编译器
  • 运算符:±*/ 之类的符号

汇编指令

具体可以参考:https://www.cdsy.xyz/computer/programme/masm/241211/cd65036.html

AT&T 和 INTEL 两种语法的主要差异有:

- AT&T INTEL
操作数方向 从左向右 从右向左
立即数表示方式 $0x01 30h
寄存器表示方式 %eax eax
助记符指定操作数长度 b8位,w16位,l32位, movl $lb, %eax mov eax, dw ptr lb
长跳转和调用 ljmp $sect, $off jmp sect:off
内存单元 圆括号 mov 5(%ebx), %eax 方括号 mov eax, [ebx + 5]
间接寻址方式 %segreg:disp(base,index,scale) segreg:[base+index*scale+disp]
注释 单行用 # 或 // 多行用 /* ... */ 只有;

AT&T 语法比较难受,但是 UNIX 类系统的源码都在用,所以还是要学习。

x86 和 x86-64 平台

这两个平台,一个是 32 位,一个是 64 位,其系统调用编号完全不同。

汇编编译器

  • NASM:INTEL 语法,跨 Linux 和 Windows 平台。
  • GNU as:默认 ATT 语法,可以通过 .intel_syntax 伪指令声明使用 INTEL 语法。
  • MASM:Windows 平台专用,不讨论。

NASM

NASM 编译器中,所有伪指令就是一般单词,没有用句点开头。

常用选项:

  • -f 选项:指定目标代码的平台,可以通过 nasm -hf 查看所有支持的。linux 常用的是 ELF32 和 ELF64
  • -o 选项:指定输出文件名字

GNU as

Unix 系列的操作系统基本默认用这个。伪指令全部用句点开头。可以直接通过 --32/--64/--x32 generate 32bit/64bit/x32 code 选项生成指定位数的代码。

Hello world 示例

NASM 编译器 + INTEL 语法

源码:

  • section .text ; 声明代码段
  • global _start ; 声明程序入口
  • _start:
  • mov eax, 4 ; 参数一:系统调用号,4表示写
  • mov ebx, 1 ; 参数二:写的目的地,1表示 stdout
  • mov ecx, msg ; 参数三:要写的字符串首地址
  • mov edx, len ; 参数四:字符串长度
  • int 80h ; 开始系统调用
  • mov eax, 1
  • mov ebx, 0
  • int 80h
  • section .data ; 声明数据段
  • msg db "hello world!", 0xA
  • len equ $ - msg

编译链接执行,链接器 LD 用 -m elf_i386 指明链接的是 32 位的目标文件:

  • nasm hello.asm -o hello.o -f elf
  • ld hello.o -o hello -m elf_i386
  • ./hello

GNU as 编译器 + AT&T 语法

  • .data # 数据段声明
  • msg : .string "Hello, world!\\n" # 要输出的字符串
  • len = . - msg # 字串长度
  • .text # 代码段声明
  • .global _start # 指定入口函数
  • _start: # 在屏幕上显示一个字符串
  • movl $len, %edx # 参数三:字符串长度
  • movl $msg, %ecx # 参数二:要显示的字符串
  • movl $1, %ebx # 参数一:文件描述符(stdout)
  • movl $4, %eax # 系统调用号(sys_write)
  • int $0x80 # 调用内核功能
  • # 退出程序
  • movl $0,%ebx # 参数一:退出代码
  • movl $1,%eax # 系统调用号(sys_exit)
  • int $0x80 # 调用内核功能

编译执行:

  • kika@kika-VirtualBox:~/test/gas$ as att.s -o att.o
  • kika@kika-VirtualBox:~/test/gas$ ld att.o -o att
  • kika@kika-VirtualBox:~/test/gas$ ./att
  • Hello, world!\n

GNU as 编译器 + INTEL 语法

这个太折腾了,建议不用

  • .intel_syntax:使用 INTEL 语法,注意寄存器前面仍然需要 %
  • .intel_syntax noprefix:使用 INTEL 语法,寄存器前面不需要 %
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
上一篇:intel汇编 和 AT&T汇编 的区别 下一篇:很抱歉没有了
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐