【无标题】

基本语法

BYTE	1
WORD	2
DWORD	4
QWORD	8
TBYTE	10

汇编程序分为三段

  • data 声明初始化的数据和常数
  • bss 声明变量 未初始化或者初始化为0的全局变量和静态变量
  • text 代码段
section .text
	global _start

section .data

section .bss

注释

  • 汇编程序注释以‘’;‘’开头,
add eax, abx ;这是注释

汇编语言声明

汇编语言包含三种类型语句

  • 可执行指令活说明
  • 汇编程序指令或伪操作
  • 宏 (代码替换)

汇编语言语法


[label]   mnemonic   [operands]   [;comment]
方括号中的字段是可选的。基本指令包括两段,第一段是要执行的指令(或助记符)的名称,第二段是命令的操作数或参数。

典型汇编语言示例

INC COUNT        ; 增加内存变量COUNT

MOV TOTAL, 48    ; 将值48转移到
                 ; 内存变量TOTAL
                 
ADD AH, BH       ; 添加寄存器BH内容
                 ; 到AH寄存器
                 
AND MASK1, 128   ; 对变量MASK1和128
                 ; 执行AND操作
                 
ADD MARKS, 10    ; 将10加到变量MARKS
MOV AL, 10       ; 将值10传送到AL寄存器

汇编指令

可执行指令

  • int 中断指令
汇编语言中的中断指令,用于触发软件中断,从而调用操作系统的系统调用

伪指令

  • db
表示“define byte”(定义字节)。它告诉汇编器在内存中分配一个或多个字节,并将这些字节初始化为指定的值。
  • equ
表示“equal”(等于)。它用于定义一个符号常量

特殊符号

  • $
这是一个特殊符号,表示当前汇编器处理到的当前位置(即当前指令的地址)

汇编语言 内存段

section关键字也可以替换成segment,会得到相同结果

segment .text
	global _start
_start:
	mov edx,len
	mov ecx.msg
	mov ebx,1
	mov eax,4
	int 0x80
	mov eax,1
	int 0x80

segment .data
msg db 'Hello,world!',0xa
len equ $ - msg 

数据段

  • .data段
全局变量,初始化的变量
  • .bss 段
静态内存部分,未初始化全局变量

代码段

  • .text
存储指令区域

堆栈

该段包含传递给程序中函数和过程的数据值

寄存器

处理器操作主要涉及处理数据。该数据可以存储在存储器中并从其访问。然而,从存储器中读取数据并将数据存储到存储器中会减慢处理器的速度,因为这涉及到通过控制总线发送数据请求并进入存储器存储单元并通过同一通道获取数据的复杂过程。为了加速处理器的运行,处理器包括一些内部存储器存储位置,称为寄存器。寄存器存储要处理的数据元素,而不必访问存储器。处理器芯片中内置了数量有限的寄存器。

通用寄存器

  • 数据寄存器
  • 指针寄存器
  • 索引寄存器
    其中一些数据寄存器在算术运算中有特定用途。
    AX是主要的累加器; 它用于输入/输出和大多数算术指令。例如,在乘法运算中,根据操作数的大小,将一个操作数存储在EAX或AX或AL寄存器中。
    BX被称为基址寄存器,因为它可以用于索引寻址。
    CX被称为计数寄存器,因为ECX,CX寄存器在迭代操作中存储循环计数。
    DX被称为数据寄存器。它也用于输入/输出操作。它还与AX寄存器以及DX一起使用,用于涉及大数值的乘法和除法运

指针寄存器

  • 堆栈指针(SP) -16位SP寄存器提供程序堆栈内的偏移值。与SS寄存器(SS:SP)关联的SP是指程序堆栈中数据或地址的当前位置
  • 基本指针(BP) -16位BP寄存器主要帮助参考传递给子例程的参数变量。SS寄存器中的地址与BP中的偏移量相结合,以获取参数的位置。BP也可以与DI和SI组合用作特殊寻址的基址寄存器。
  • 指令指针(IP) -16位IP寄存器存储要执行的下一条指令的偏移地址。与CS寄存器关联的IP(作为CS:IP)给出了代码段中当前指令的完整地址。

控制寄存器

通用标志位是:
溢出标志(OF) -指示有符号算术运算后数据的高阶位(最左位)的溢出。
方向标记(DF) -它确定向左或向右移动或比较字符串数据的方向。DF值为0时,字符串操作为从左至右的方向;当DF值为1时,字符串操作为从右至左的方向。
中断标志(IF) -确定是否忽略或处理外部中断(例如键盘输入等)。当值为0时,它禁用外部中断,而当值为1时,它使能中断。
陷阱标志(TF) -允许在单步模式下设置处理器的操作。我们使用的DEBUG程序设置了陷阱标志,因此我们可以一次逐步执行一条指令。
符号标志(SF) -显示算术运算结果的符号。根据算术运算后数据项的符号设置此标志。该符号由最左位的高位指示。正结果将SF的值清除为0,负结果将其设置为1。
零标志(ZF) -指示算术或比较运算的结果。非零结果将零标志清零,零结果将其清零。
辅助进位标志(AF) -包含经过算术运算后从位3到位4的进位;用于专业算术。当1字节算术运算引起从第3位到第4位的进位时,将设置AF。
奇偶校验标志(PF) -指示从算术运算获得的结果中1位的总数。偶数个1位将奇偶校验标志清为0,奇数个1位将奇偶校验标志清为1。
进位标志(CF) -在算术运算后,它包含一个高位(最左边)的0或1进位。它还存储移位或旋转操作的最后一位的内容。
下表列出了16位标志寄存器中标志位的位置

段寄存器

段是程序中定义的特定区域,用于包含数据,代码和堆栈。有三个主要部分-
代码段 - 它包含所有要执行的指令。16位代码段寄存器或CS寄存器存储代码段的起始地址。
数据段 - 它包含数据,常量和工作区。16位数据段寄存器或DS寄存器存储数据段的起始地址。
堆栈段 - 它包含数据或过程或子例程的返回地址。它被实现为“堆栈”数据结构。堆栈段寄存器或SS寄存器存储堆栈的起始地址

系统调用

系统调用是用户空间和内核空间之间接口的API
您可以在汇编程序中使用Linux系统调用。您需要执行以下步骤才能在程序中使用Linux系统调用-

寻址模式

大多数汇编语言指令都需要处理操作数。操作数地址提供了要处理的数据存储的位置。。有些指令不需要操作数,而另一些指令则需要一个,两个或三个操作数。当一条指令需要两个操作数时,第一个操作数通常是目的地,它在寄存器或存储器位置中包含数据,第二个操作数是源。源包含要传递的数据(立即寻址)或数据的地址(在寄存器或存储器中)。通常,操作后源数据保持不变。
寻址的三种基本模式是-

  • 寄存器寻址
  • 立即寻址
  • 内存寻址

寄存器寻址

在这种寻址模式下,寄存器包含操作数。根据指令,寄存器可以是第一个操作数,第二个操作数或两者。


MOV DX, TAX_RATE   ; 寄存器是第一个操作数
MOV COUNT, CX      ; 寄存器是第二个操作数
MOV EAX, EBX       ; 两个操作数都是寄存器

由于寄存器之间的数据处理不涉及内存,因此可以最快地处理数据

立即寻址

立即数操作数具有常量值或表达式。当具有两个操作数的指令使用立即寻址时,第一个操作数可以是寄存器或存储器位置,而第二个操作数是立即数。第一个操作数定义数据的长度


BYTE_VALUE  DB  150    ; 一个字节值被定义
WORD_VALUE  DW  300    ; 一个字值被定义
ADD  BYTE_VALUE, 65    ; BYTE_VALUE加一个立即操作数65
MOV  AX, 45H           ; 立即常数45H转移到AX

直接内存寻址

在存储器寻址模式下指定操作数时,通常需要直接访问主存储器,通常是数据段。。这种寻址方式导致数据处理变慢。为了找到数据在内存中的确切位置,我们需要段起始地址(通常在DS寄存器中找到)和偏移值。此偏移值也称为有效地址。在直接寻址模式下,偏移量值直接作为指令的一部分指定,通常由变量名指示。


ADD     BYTE_VALUE, DL  ; 将寄存器添加到存储位置
MOV     BX, WORD_VALUE  ; 将内存中的操作数添加到寄存器中

直接偏移寻址

此寻址模式使用算术运算符修改地址。例如,查看以下定义数据表的定义-

BYTE_TABLE DB  14, 15, 22, 45      ; 字节表
WORD_TABLE DW  134, 345, 564, 123  ; 字表

以下操作将数据从内存中的表访问到寄存器中-

MOV CL, BYTE_TABLE[2]   ; 获取BYTE_TABLE的第三个元素
MOV CL, BYTE_TABLE + 2  ; 获取BYTE_TABLE的第三个元素
MOV CX, WORD_TABLE[3]   ; 获取WORD_TABLE的第4个元素
MOV CX, WORD_TABLE + 3  ; 获取WORD_TABLE的第4个元素

间接内存寻址

此寻址模式利用计算机的Segment:Offset寻址功能。通常,在方括号内编码的基址寄存器EBX,EBP(或BX,BP)和索引寄存器(DI,SI)用于内存引用。


MY_TABLE TIMES 10 DW 0  ; 分配10个字(2个字节),每个字都初始化为0
MOV EBX, [MY_TABLE]     ; EBX中MY_TABLE的有效地址
MOV [EBX], 110          ; MY_TABLE[0] = 110
ADD EBX, 2              ; EBX = EBX +2
MOV [EBX], 123          ; MY_TABLE[1] = 123

MOV指令

MOV destination, source
MOV指令可能具有以下五种形式之一-


MOV  寄存器, 寄存器
MOV  寄存器, 立即数
MOV  寄存器, 内存
MOV  内存, 立即数
MOV  内存, 寄存器

汇编语言 变量

NASM提供了各种定义指令来为变量保留存储空间。define assembler指令用于分配存储空间。它可以用于保留以及初始化一个或多个字节。
为初始化数据分配存储空间
初始化数据的存储分配语句的语法为-

[variable-name]    define-directive    initial-value   [,initial-value]...

其中,变量名是每个存储空间的标识符。汇编器为数据段中定义的每个变量名称关联一个偏移值
define指令有五种基本形式-
指令 目的 储存空间
DB 定义字节 分配1个字节
DW 定义字 分配2个字节
DD 定义双字 分配4个字节
DQ 定义四字 分配8个字节
DT 定义十个字节 分配10个字节
以下是一些使用define指令的示例-


choice          DB      'y'
number          DW      12345
neg_number      DW      -12345
big_number      DQ      123456789
real_number1    DD      1.234
real_number2    DQ      123.456

请注意
字符的每个字节均以十六进制形式存储为其ASCII值。
每个十进制值都将自动转换为其等效的16位二进制数,并以十六进制数形式存储。
处理器使用小尾数字节顺序。
负数将转换为其2的补码表示形式。
短浮点数和长浮点数分别使用32位或64位表示

为未初始化的数据分配存储空间

reserve指令用于为未初始化的数据保留空间。reserve指令采用单个操作数,该操作数指定要保留的空间单位数。每个define指令都有一个相关的reserve指令。
保留指令有五种基本形式-
指令 目的
RESB 保留一个字节
RESW 保留字
RESD 保留双字
RESQ 保留四字
REST 保留十个字节

多种定义

一个程序中可以有多个数据定义语句。

choice    DB    'Y'              ;ASCII of y = 79H
number1   DW    12345    ;12345D = 3039H
number2    DD  12345679  ;123456789D = 75BCD15H

多重初始化

TIMES指令允许多次初始化为相同的值。例如,可以使用以下语句定义一个大小为9的标记的数组并将其初始化为零-


marks  TIMES  9  DW  0

section .text
   global _start        ;must be declared for linker (ld)
        
_start:                 ;tell linker entry point
   mov  edx,9           ;message length
   mov  ecx, stars      ;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
stars   times 9 db '*'

汇编常量

NASM提供了几个定义常量的指令。在前面的章节中,我们已经使用过EQU指令。我们将特别讨论三个指令-

  • EQU
  • %assign
  • %define
    EQU指令
    EQU指令用于定义常量。EQU指令的语法如下-
CONSTANT_NAME EQU expression

%assign 指令
在%assign 指令可以用来定义数字常量像EQU指令。该指令允许重新定义。例如,您可以将常量TOTAL定义为-

%assign TOTAL 10

%define指令
在 %define 指令允许定义数值和字符串常量。该指令类似于C中的#define。例如,您可以将常量PTR定义为-

%define PTR  [EBP+4]

算数指令

INC 指令

INC指令用于将操作数加1。它对可以在寄存器或内存中的单个操作数起作用。
INC指令具有以下语法

INC destination

DEC指令

DEC指令用于将操作数减1。它对可以在寄存器或内存中的单个操作数起作用。
DEC指令具有以下语法-

DEC destination

ADD & SUB指令

DD和SUB指令用于对字节,字和双字大小的二进制数据进行简单的加/减,即分别用于添加或减去8位,16位或32位操作数。
ADD和SUB指令具有以下语法-

ADD/SUB destination, source

ADD / SUB指令可以发生在-
寄存器 to 寄存器
内存 to 寄存器
寄存器 to 内存
寄存器 to 常量数据
内存 to 常量数据

MUL / IMUL指令

有两条指令用于将二进制数据相乘。MUL(乘法)指令处理未签名的数据,而IMUL(整数乘法)则处理签名的数据。两条指令都影响进位和溢出标志。

MUL/IMUL multiplier

DIV / IDIV指令

除法运算生成两个元素-商和余数,如果是乘法,则不会发生溢出,因为使用了双倍长度寄存器来保持乘积

DIV/IDIV        divisor

逻辑指令

指令 格式
AND AND 操作数1,操作数2
OR OR 操作数1,操作数2
XOR XOR 操作数1,操作数2
TEST TEST 操作数1,操作数2
NOT NOT 操作数1
在所有情况下,第一个操作数都可以在寄存器或内存中。第二个操作数可以是寄存器/内存,也可以是立即数(常数)。但是,内存到内存操作是不可能的。这些指令比较或匹配操作数的位,并设置CF,OF,PF,SF和ZF标志。

AND 指令

AND 指令用于通过执行按位AND运算来支持逻辑表达式。如果两个操作数的匹配位均为1,则按位AND运算返回1,否则返回0。例如-

TEST 指令

与AND运算的工作原理相同,但与AND指令不同的是,它不会更改第一个操作数。因此,如果我们需要检查寄存器中的数字是偶数还是奇数,我们也可以使用TEST指令执行此操作,而无需更改原始数字

TEST    AL, 01H
JZ      EVEN_NUMBER

NOT 指令

NOT 指令实现按位NOT运算。NOT操作将操作数中的位取反。操作数可以在寄存器中,也可以在存储器中。
例如,

条件指令

汇编语言中的条件执行是通过几个循环和分支指令来完成的。这些指令可以更改程序中的控制流。在两种情况下观察到条件执行

  • 无条件跳转 - 这是通过JMP指令执行的。条件执行通常涉及将控制权转移到不遵循当前执行指令的指令的地址。控制权的转移可以是前进的(执行新的指令集),也可以是后退的(重新执行相同的步骤)。
  • 无条件跳转 - 这取决于条件由一组跳转指令j 执行。条件指令通过中断顺序流程来转移控制,而它们通过更改IP中的偏移值来进行控制。
    让我们在讨论条件指令之前先讨论CMP指令

CMP指令

CMP 指令比较两个操作数。它通常用于条件执行中。该指令基本上从另一个操作数中减去一个操作数,以比较操作数是否相等。它不会干扰目标或源操作数。它与条件跳转指令一起用于决策

CMP destination, source

CMP 通常用于比较计数器值是否已达到需要运行循环的次数。考虑以下典型条件-

INC     EDX
CMP     EDX, 10 ; 比较计数器是否达到10
JLE     LP1     ; 如果它小于或等于10,则跳转到LP1

无条件跳转

如前所述,这是通过JMP指令执行的。条件执行通常涉及将控制权转移到不遵循当前执行指令的指令的地址。控制权的转移可以是前进的(执行新的指令集),也可以是后退的(重新执行相同的步骤)。
句法
JMP 指令提供了一个标签名称,控制流将立即转移到该标签名称。JMP指令的语法是-

JMP     label

以下代码段说明了JMP指令


MOV  AX, 00    ; 将AX初始化为0
MOV  BX, 00    ; 将BX初始化为0
MOV  CX, 01    ; 初始化CX为1
L20:
ADD  AX, 01    ; 增量AX
ADD  BX, AX    ; 将AX添加到BX
SHL  CX, 1     ; 向左移动CX,这反过来使CX的值翻倍
JMP  L20       ; 重复的语句

条件跳转
如果在条件跳转中满足某些指定条件,则控制流将转移到目标指令。根据条件和数据,有许多条件跳转指令。
以下是用于算术运算的有符号数据的条件跳转指令-

指令	描述	标志测试
JE/JZ	跳转等于或跳转零	ZF
JNE/JNZ	跳转不等于或跳转不为零	ZF
JG/JNLE	跳转大于或跳转不小于/等于	OF,SF,ZF
JGE/JNL	跳转大于/等于或不小于跳转	OF,SF
JL/JNGE	跳转小于或不大于/等于	OF,SF
JLE/JNG	跳少/等于或跳不大于	OF,SF,ZF

以下是对用于逻辑运算的无符号数据使用的条件跳转指令-

指令	描述	标志测试
JE/JZ	跳转等于或跳转零	ZF
JNE/JNZ	跳转不等于或跳转不为零	ZF
JA/JNBE	跳转向上或不低于/等于	CF,ZF
JAE/JNB	高于/等于或不低于	CF
JB/JNAE	跳到以下或跳到不高于/等于	CF
JBE/JNA	跳到下面/等于或不跳到上方	AF,CF

以下条件跳转指令有特殊用途,并检查标志的值-

指令	描述	标志测试
JXCZ	如果CX为零则跳转	没有
JC	如果携带则跳	CF
JNC	如果不携带则跳转	CF
JO	溢出时跳转	OF
JNO	如果没有溢出则跳转	OF
JP/JPE	跳校验或偶校验	PF
JNP/JPO	跳转无奇偶校验或跳转奇偶校验	PF
JS	跳跃符号(负值)	SF
JNS	跳转无符号(正值)	SF

循环指令

JMP指令可用于实现循环。例如,以下代码段可用于执行循环主体10次。

MOV     CL, 10
L1:
<LOOP-BODY>
DEC     CL
JNZ     L1

但是,处理器指令集包括一组用于实现迭代的循环指令。基本的LOOP指令具有以下语法-

LOOP    label

函数

过程或子例程在汇编语言中非常重要,因为汇编语言程序往往会很大。程序由名称标识。在此名称之后,将描述执行明确定义的作业的过程主体。该过程的结束由return语句指示。
以下是定义过程的语法-

proc_name:
   procedure body
   ...
   ret

通过使用CALL指令从另一个函数调用该过程。CALL指令应将被调用过程的名称作为参数,如下所示-

CALL proc_name

被调用过程通过使用RET指令将控制权返回给调用过程。

堆栈数据结构

堆栈是内存中类似数组的数据结构,可以在其中存储数据并从称为“堆栈顶部”的位置删除数据。需要存储的数据被“推送”到堆栈中,要检索的数据从堆栈中“弹出”。堆栈是一种LIFO数据结构,即首先存储的数据最后被检索。汇编语言为堆栈操作提供了两条指令:PUSH和POP。这些指令的语法如下-

PUSH    operand
POP     address/register

堆栈段中保留的内存空间用于实现堆栈。寄存器SS和ESP(或SP)用于实现堆栈。SS:ESP寄存器指向堆栈的顶部,该顶部指向插入到堆栈中的最后一个数据项,其中SS寄存器指向堆栈段的开头,而SP(或ESP)将偏移量设置为堆栈段。
堆栈实现具有以下特征-
只能将字或双字保存到堆栈中,而不是字节。
堆栈朝反方向增长,即朝着较低的存储器地址增长
堆栈的顶部指向插入堆栈中的最后一个项目。它指向插入的最后一个字的低字节。
正如我们所讨论的,在将寄存器的值用于某些用途之前将其存储在堆栈中;它可以通过以下方式完成-


; 将AX和BX寄存器内容保存在堆栈中
PUSH    AX
PUSH    BX

;将寄存器用着其他用途
MOV     AX, VALUE1
MOV     BX, VALUE2
...
MOV     VALUE1, AX
MOV     VALUE2, BX

;使用完之后恢复寄存器原始值
POP     BX
POP     AX

汇编 递归

汇编 宏

编写宏是确保使用汇编语言进行模块化编程的另一种方法。
宏是由名称分配的指令序列,可以在程序中的任何位置使用。
在NASM中,宏使用%macro和%endmacro指令定义。
宏以%macro指令开头,以%endmacro指令结尾。

%macro macro_name  number_of_params
<macro body>
%endmacro
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值