汇编教程二(Intel 风格语法)
https://www.tutorialspoint.com/assembly_programming/assembly_basic_syntax.htm
Intel x86 Assembly - 基础语法
本教程主要用的编译器的NASM ,NASM 采用的是Intel风格语法
Intel 汇编程序可以分为三个部分
-
data部分
-
bss部分
-
text 部分.
data部分
data部分用于声明初始化数据或常量。此数据在运行时不会更改。您可以在此部分声明各种常量值、文件名或缓冲区大小等。
声明数据部分的语法是 -
section .data
bss 部分
bss部分用于声明变量。声明 bss 部分的语法是 -
section .bss
text 部分
text部分用于保存实际代码。此部分必须以声明global _start开始,它告诉内核程序执行从哪里开始。
声明text部分的语法是 -
section .text global _start _start:
注释
Intel风格语法汇编语言注释以分号 (;) 开头。它可能包含任何可打印字符,包括空白。它可以单独出现在一行中,例如 :
; This program displays a message on screen
或者,在同一行上连同一条指令,比如 :
add eax, ebx ;adds ebx to eax
而 GNU gas(as)采用的是#作为注解。
Intel x86汇编语言声明
汇编语言程序由三种类型的声明语句组成 -
- 可执行指令或指令
- 汇编程序指令或伪操作
- 宏.
可执行指令或简单指令告诉处理器做什么。每条指令都包含一个操作码(opcode)。每条可执行指令生成一条机器语言指令。 每条可执行指令生成一条机器语言指令。
汇编程序指令或伪操作告诉汇编程序有关汇编过程的各个方面。这些是不可执行的,不会生成机器语言指令
宏基本上是一种文本substitution机制
Intel汇编语言语句的声明语法
Assembly language statements are entered one statement per line. Each statement follows the following format −
汇编语言语句每行输入一个声明语句。每个语句都遵循以下格式 -
[label] mnemonic [operands] [;comment]
方括号中的字段是可选的。一条基本指令有两部分,第一部分是要执行的指令(或助记符)的名称,第二部分是操作数或命令的参数。
以下是典型的汇编语言语句的一些示例 :
INC COUNT ; Increment the memory variable COUNT
MOV TOTAL, 48 ; Transfer the value 48 in the
; memory variable TOTAL
ADD AH, BH ; Add the content of the
; BH register into the AH register
AND MASK1, 128 ; Perform AND operation on the
; variable MASK1 and 128
ADD MARKS, 10 ; Add 10 to the variable MARKS
MOV AL, 10 ; Transfer the value 10 to the AL register
实验环境:
[root@ht6 1]# nasm -v NASM version 2.10.07 compiled on Jun 9 2014 [root@ht6 1]# uname -r 3.10.0-1160.62.1.el7.x86_64 [root@ht6 1]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [root@ht6 1]# as -v GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version 2.27-44.base.el7_9.1 [root@ht6 1]# gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper Target: x86_64-redhat-linux Configured with: ../configure --prefix=/usr --mandir=/usr/share/man .... Thread model: posix gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
平台是x86-64架构的linux操作系统,内核 x86_64
一、Intel x86-32 汇编的样例程序(Intel风格语法)
test.c汇编程序 (注意程序是针对的32位的寄存器编写,采用的Intel风格语法,从右到左赋值)
section .text global _start ;must be declared for linker (ld) _start: ;tells linker entry point mov edx,len ;message length mov ecx,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel section .data msg db 'Hello, world!', 0xa ;string to be printed len equ $ - msg ;length of the string
test.asm使用NASM(默认是Intel风格语法)编译和链接test.asm汇编程序
[root@ht6 1]# yum install nasm //如果没有,安装很简单
Nasm编译步骤如下:
首先确保已在 PATH 环境变量中设置nasm和ld二进制文件的路径。现在,按照以下步骤编译和链接上述程序 :
-
使用vim 键入以上代码并将其保存为 test.asm。//这里是.asm 而不是.s后缀
-
确保您与保存hello.asm 的目录位于同一目录中。
-
输入命令 : nasm -f elf64 test.asm
-
如果有任何错误,系统会在此阶段提示您。否则,将创建名为hello.o的程序目标文件。
-
要链接目标文件并创建名为 test的可执行文件,请键入ld -m elf_i386 -s -o test test.o
-
通过键入./test来执行程序。
我们也可以直接运行 nasm -f elf64 test.asm && ld test.o && ./a.out
实验过程:
[root@ht6 2]# nasm -f elf test.asm && ld test.o && ./a.out
ld: i386 architecture of input file `test.o' is incompatible with i386:x86-64 output
[root@ht6 1]# nasm -f elf64 test.asm && ld test.o && ./a.out //在x86-64平台上编译,必须改成elf64
Hello, world!
[root@ht6 2]# ls
a.out test.asm test.o
[root@ht6 2]# file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
小结:利用x86-64平台编译,结果兼容x86-32程序
二、Intel x86-64 汇编的样例程序(Intel风格语法)
样例来自: https://montcs.bloomu.edu/Information/LowLevel/Assembly/hello-asm.html
样例2: test1.asm(本汇编程序是针对的64位的寄存器进行编写的,风格采用的是Intel)
register用到了 rax、rdi、rsi、rdx等64-bits寄存器
; ---------------------------------------------------------------------------------------- ; Writes "this is test x86-64" to the console using only system calls. Runs on 64-bit Linux only. ; To assemble and run: ; ; nasm -felf64 test1.asm && ld test1.o && ./a.out ; ---------------------------------------------------------------------------------------- global _start section .text _start: mov rax, 1 ; system call for write mov rdi, 1 ; file handle 1 is stdout mov rsi, message ; address of string to output mov rdx, 13 ; number of bytes syscall ; invoke operating system to do the write mov rax, 60 ; system call for exit xor rdi, rdi ; exit code 0 syscall ; invoke operating system to exit section .data message: db "Hello, World", 10 ; note the newline at the end
实验过程:
[root@ht6 1]# nasm -f elf64 test1.asm && ld test1.o && ./a.out Hello, World [root@ht6 1]# file test1.asm test1.asm: ASCII text [root@ht6 1]# file a.out a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
三、GCC(AS) x86-64 汇编的样例程序(风格语法为AT&T)
样例3: 本例用gcc来进行编译
aozhejin.s (本汇编程序是针对的64位寄存器编写的,语法风格采用的是AT&T,所以用gcc(as)来进行编译)
# ---------------------------------------------------------------------------------------- # Writes "this is test" to the console using only system calls. Runs on 64-bit Linux only. # To assemble and run: # # gcc -c aozhejin.s && ld aozhejin.o && ./a.out # # or # # gcc -nostdlib aozhejin.s && ./a.out # ---------------------------------------------------------------------------------------- .global _start .text _start: # write(1, message, 13) mov $1, %rax # system call 1 is write mov $1, %rdi # file handle 1 is stdout mov $message, %rsi # address of string to output mov $13, %rdx # number of bytes syscall # invoke operating system to do the write # exit(0) mov $60, %rax # system call 60 is exit xor %rdi, %rdi # we want return code 0 syscall # invoke operating system to exit message: .ascii "this is test\n"
实验过程:
[root@ht5 s]# gcc -c aozhejin.s && ld aozhejin.o && ./a.out //编译通过
this is test
指令
汇编代码是很多条指令的序列,一个指令可以完成一个CPU操作。那我们就先来细细研究一下单条指令的特征和格式。
一条指令由操作码和0~2个操作数构成。操作码指定了当前指令要执行的操作,如将两数相加,操作数则是操作码的作用对象。因此可以看出,指令的长度不固定,短则1个字节,长则15字节。
1.操作码(opcode)
操作码是指令的第一部分,它告诉计算机执行什么功能,也称为 操作码。操作码是保存提供给计算机系统的指令的数字代码。 这些指令描述了 CPU 要执行的操作。计算机系统为赋予它的每个功能都有一个操作码或操作码。
2.操作数(operand)
操作数是指令的另一个第二部分,它指示计算机系统到哪里去寻找数据或指令,或将数据或指令存储到哪里。 操作数的数量因不同的计算机系统而异。每条指令指示计算机系统的控制单元要执行什么以及如何执行。 这些操作是算术、逻辑、分支操作等,具体取决于提供给计算机的问题。
下面的样例只能运行在x86-32位的处理器上
;Copyright (c) 1999 Konstantin Boldyshev <konst@linuxassembly.org> ; ;"hello, world" in assembly language for Linux ; ;to build an executable: ; nasm -f elf hello.asm //如果想运行在x86-64平台需更换为 elf64 ; ld -s -o hello hello.o section .text ; Export the entry point to the ELF linker or loader. The conventional ; entry point is "_start". Use "ld -e foo" to override the default. global _start section .data msg db 'Hello, world!',0xa ;our dear string len equ $ - msg ;length of our dear string section .text ; linker puts the entry point here: _start: ; Write the string to stdout: mov edx,len ;message length mov ecx,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel ; Exit via the kernel: mov ebx,0 ;process' exit code mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel - this interrupt won't return

浙公网安备 33010602011771号