首页 > 编程语言 >8086汇编(16位汇编)学习笔记09.宏汇编

8086汇编(16位汇编)学习笔记09.宏汇编

时间:2024-12-29 13:26:16浏览次数:8  
标签:汇编 8086 16 bx mov seg 指令 ax data

8086汇编(16位汇编)学习笔记09.宏汇编-C/C++基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net

宏汇编在文件中是当做关键字的,但是在bug中运行时并没有这些指令,这些关键词被称为伪指令,cpu并不认识他们,需要经过编译器转化成 cpu认识的代码,但是他多我们写代码帮助又很大

表达式

表达式中的求值是在程序链接时完成的,所以表达式中的各值必须是在汇编或链接期就能确定,也就是 说不能将寄存器或者变量运⽤于表达式。

算术表达式

运算符意义例⼦
+65 + 32
-size val - 54
*23h * 65h
/98 / 45
mod取模99 mod 65
mov ax, 54+65
mov ax, 65-48
mov ax, 65*78
mov ax, type byte * 78
mov ax, 78 mod 5
mov ax, 96 / 5
mov ax, size g_buf / type g_buf

;mov ax,bx+7   ;这个是错的,因为编译器无法得到结果,不知道bx的值

image.png

逻辑运算符

逻辑运算即位运算,逻辑运算符与对应的指令助记符单词是相同的,当它们出现在操作码部分时是指 令,出现在操作数时是逻辑运算符

运算符意义
and位与
or位或
not按位取反
xor异或
mov ax, 5566h and 6655h
mov ax, 7788h or 8877h
mov ax, not 5566h
mov ax, 5566h xor 7788h

image.png

关系运算符

关系运算符的结果,如果结果为真,则所有位都置为1,即FFFF;否则所有位都置为0,即 .

运算符英⽂意义
EQequal等于 ==
NEnot equal不等于 !=
GTgreater than⼤于 >
LTless than⼩于 <
GEgreater than or equal⼤于等于 >=
LEless than or equal⼩于等于 <=
mov bx,88 eq 88    ;bx= 0FFFFh   因为结果为ture
 mov bx,88 ne 88    ;bx= 0000h    因为结果为flase
 mov bx,88 ge 88    ;bx= 0FFFFh   因为结果为ture

img

标号

匿名标号 @@
  • @@是匿名标号
  • @b 向上查找最近的@@, b是back
  • @f 向下查找最近的@@ ,f是front

一般我们用 jmp 跳转你需要有标号,而且标号名必须唯一 ,但是如果 标号名是 @@ ,那么就可以重复,跳转用 @b 或 @f , @@ 的 跳转距离在段内是 没有限制的

img

调整偏移量指令 ORG

格式 ORG 偏移值

此指令后的下⼀个变量或指令从 偏移值 开始存放,即把一个变量或者指令放在指定的偏移内,可以提前,也可以延后

;这是栈段
stack segment stack
  db 512 dup(0)
stack  ends

;这是数据段
data segment
  g_buf db "hello world"

  org  20 
  g_buf1 db "hello world"  ;表示 g_buf1 会从段偏移20的地方开始存放

  org  0  
  g_buf2 db "111111"     ;表示 g_buf2 会从段偏移0的地方开始存放,回覆盖 g_buf的数据

data ends

;这里是代码
CODE segment

START:
    assume ds:data
    mov ax, data
    mov ds, ax
  
  
    org 20h
    mov ax,4C00H  ; 带参数返回的退出   ;此处代码从20H 处开始存放,后面指令依次后推
    int 21h   ;使用21号中断
   
CODE ends

end START

img

当前地址指令$
  • $伪指令代表当前指令或变量的地址
  • 常⽤于计算缓冲区⻓度和获取当前ip值
  • 可与 ORG 配合使⽤
data_seg segment
  g_buf dw 10h dup(0)
  g_len dw $ - offset g_buf  ;获取上⾯的g_buf的⻓度
  org $ + 10h                ;下⼀个变量从当前地址+10h的偏移开始存放
  g_w dw 65h
    
data_seg ends

CODE segment

START:

 org 100h
 mov ax, 5566h and 6655h ;此指令从代码段偏移100h开始存放
 mov ax, $ ;获取 本条指令的地址
 mov ax, $+4;获取 本条指令的地址+4
 mov ax, 4c00h
 int 21h
   
CODE ends

结构体 struc

格式

结构体名 struc

;这⾥定义结构体成员

结构体名 ends

结构体使⽤<>来初始化

结构体可以通过变量名和寄存器来访问成员

结构体可以在定义时候初始化,也可以在后面初始化

结构作为局部变量无法赋初值

;定义结构体
Point struc
    m_wX dw 0
    m_wY dw 0
Point ends

;关键字  struc,可以在定义时候赋初值
TagStu struc
    m_byte db 0
    m_w    dw 5656h
    m_ary  db 8 dup(0)
    m_sz   db "hello"
    m_pt   Point <>      ;结构体里面嵌套结构体
TagStu ends

;堆栈
stack_seg segment stack
    db 512 dup(0)
stack_seg ends

;数据段
data_seg segment
    g_stu TagStu <66h, 7777h, "testtest", "66", <11h, 22h>>   ;初始化结构体
    g_ary Point 12 dup(<11h, 22h>)                            ;定义结构体数组
data_seg ends

;代码
code_seg segment

;结构体传参,直接传对象,它会将结构提对象入栈,每次入栈2字节(推荐用指针)
Foo0  PROC far c stu:TagStu
    lea bx, stu

    mov stu.m_byte, 99h     ;修改结构体成员的值
    mov stu.m_w, 6666h      ;修改结构体成员的值

    ret  
Foo0  ENDP

;结构体传参,传对象指针,通过指针访问必须借助寄存器,不能直接用指针
Foo1 PROC far c pStu:ptr TagStu

    ;mov ax, [pStu]m_w   ;指针,不能直接点使用,必须通过寄存器
  
    mov bx, pStu         ;将结构体指针赋值给bx

    ;通过结构体指针访问结构体成员
    assume bx:ptr TagStu     ;将bx解释为 TagStu 结构体指针,类似强转
    mov ax, [bx].m_w         ;通过结构体指针访问成员 
    assume bx:nothing        ;将bx 的 解释方式转回默认 

    ret  
Foo1 ENDP

;结构体作为局部变量,局部变量无法赋初值
foo PROC far c 
    local @stu:TagStu   ;变量类型直接是结构体类型

    lea bx, @stu         ;获取变量的偏移地址
    mov al, @stu.m_byte  ;访问变量成员
    mov ax, @stu.m_w     ;访问变量成员

   ret 
foo ENDP

START:
    assume ds:data_seg
    mov ax, data_seg
    mov ds, ax

    mov ax, g_stu.m_pt.m_wX   ;访问结构体内 结构体的的成员

    invoke Foo1, offset g_stu  ;结构体指针作为函数参数 

    invoke Foo0, g_stu         ;结构体对象作为函数参数
 
    invoke foo                 ;结构体作为局部变量

    mov al, g_stu.m_byte      ;访问结构体成员 
    mov ax, g_stu.m_w         ;访问结构体成员
    lea bx, g_stu.m_ary       ;获取结构体成员的偏移地址
    mov byte ptr [bx], 'a'    ;修改结构体成员的值

    mov ax, 4c00h;
    int 21h
code_seg ends
end START

img

img

equ语句

作用:用来定义宏

不可以重命名

可⽤于常量和表达式

可⽤于字符串

可⽤于指令名,给指令取别名

可⽤于类型,给类型取别名

可⽤于操作数

;是无参宏,没有参数

;堆栈
stack_seg segment stack
    db 512 dup(0)
stack_seg ends

PI equ 314                  ;常量
SZNAME equ "hello world"    ;字符串
MYMOV equ mov               ;指令名
CHAR equ db                 ;类型
INT16 equ dw                ;类型

;PI equ 6677h ;不允许再次定义

;数据段
data_seg segment
    g_sz CHAR SZNAME
    g_w  INT16 PI
    g_w2 INT16 44h
data_seg ends

;代码
code_seg segment

START:
    assume ds:data_seg
    mov ax, data_seg
    mov ds, ax

    MYMOV ax, g_w

    mov ax, 4c00h;
    int 21h
code_seg ends
end START

img

=语句

可以被修改

只能⽤于常数

COUNT2 = 100h   ;后跟数值
COUNT2 = 200h   ;可以再次赋值

;szTest = "hello world"  ;错误,不能用于字符串,只能用于立即数(常量)

mov ax, COUNT2


;可以用来提高可读性

MYFUNC:
nX = 2
nY = 4
    push bp
    mov bp, sp
    sub sp, 10

    mov [bp-nX], ax
    mov [bp-nY], ax

    mov sp, bp
    pop bp
    ret
macro语句
格式

宏名 macro [参数1][,参数2]...

宏体

endm

宏会在使⽤的地⽅展开

宏可以带参数

字符串拼接使⽤&

;堆栈
stack_seg segment stack
    db 512 dup(0)
stack_seg ends


CHAR equ db 
INT16 equ dw

;内存到内存赋值宏
movm macro val1, val2
    push val1
    pop val2
endm

;字符串拼接
shift macro d, opt, count
    push cx
    mov cl, count
    sa&d opt, cl
    pop cx
endm


;数据段
data_seg segment
    g_w  INT16 55H
    g_w2 INT16 44h
data_seg ends

;代码
code_seg segment


START:
    assume ds:data_seg
    mov ax, data_seg
    mov ds, ax

  
    ;内存到内存赋值
    movm g_w, g_w2
    movm g_w2, g_w

    shift r, ax, 2
    shift r, ax, 5
    shift l, bx, 4
    shift l, dx, 2


    mov ax, 4c00h;
    int 21h
code_seg ends

end START

img

img

多文件编译

1.源文件
  • 源文件后缀名为asm
  • 每个源文件末尾需要有end
2.头文件
  • 汇编头文件后缀名为inc

  • 头文件包含 include xxx.inc

  • 头文件防重复包含

    ifndef SECOND_1
    SECOND_1 equ 1
    	Func1 proto far stdcall arg1 : word, arg2 : word
        extern g_dw : word
    endif
    
3.函数使用

函数在源文件定义,在头文件中声明即可。

4.全局变量

全局变量在定义文件中必须使用public指明此变量为全局public变量名

全局变量在使用文件中必须使用extern 指明此变量来自外部文件 extern 变量:类型

ifndef HEADER_INC    ;防止重复包含
HEADER_INC equ 1

   extern g_w:word  ;声明明 g_w 是来自外部的全局变量

endif
public g_w    ;指名 g_w 是全局变量 ,不然默认本文件内才能使用(文件作用域)

data_seg segment
    g_w dw 0
data_seg ends

end
5.编译
ml /c xx.asm yy.asm
link xx.obj yy.obj
或
ml *.asm

伪指定实现分支,循环

img

分支

格式

格式1:

.IF condition    ;以英文“句号”开头   ;条件"condition"成立时所执行的指令序列

  指令序列   

.ENDIF

格式2:

.IF condition  ;条件"condition"不成立时所执行的指令序列

  指令序列1

.ELSE

  指令序列2   

.ENDIF

格式3:

.IF condition1

  指令序列1

.ELSEIF condition2 ;条件"condition2"成立时所执行的指令序列

  指令序列2    

.ENDIF

其中:条件表达式“condition”的书写方式与C语言中条件表达式的书写方式相似,也可用括号来组成复杂的条件表达式。

条件表达式中可用的操作符有:==(等于)、!=(不等)、>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、&(位操作与)、!(逻辑非)、&&(逻辑与)、||(逻辑或)等。

;堆栈
stack_seg segment stack
    db 512 dup(0)
stack_seg ends

;数据段
data_seg segment

data_seg ends

;代码
code_seg segment

START:
    assume ds:data_seg
    mov ax, data_seg
    mov ds, ax

    mov g_w, 8

    .if ax >= bx
        xor ax, ax
    .elseif ax <= bx
        xor bx, bx
    .else 
        xor cx, cx
    .endif

    mov ax, 4c00h;
    int 21h
code_seg ends

end START

1、WHILE型循环伪指令

.WHILE condition ;条件"condition”成立时所执行的指令序列
  循环体的指令序列    
.ENDW

其中:.ENDW与前面的.WHILE相匹配,它标志着其循环体到此结束。

如果条件表达式“condition”在循环开始时,就为“假”(false),那么,该循环体一次也不会被执行。

2、REPEAT型循环伪指令

.REPEAT
  循环体的指令序列
.UNTIL condition .REPEAT
  循环体的指令序列
.UNTILCXZ [condition]

REPEAT型循环在执行完循环体后,才判定逻辑表达式condition的值。若该表达式的值为真,则终止该循环,并将执行伪指令.UNTIL[CXZ]后面的指令,否则,将向上跳转到伪指令.REPEAT之后的指令,为继续执行其循环体作准备

循环终止 break 和继续 continue

(1)、终止循环伪指令
.BREAK

.BREAK .IF condition

该伪指令用来终止包含它的最内层循环。前者是无条件终止循环,后者是仅当逻辑表达式condition为真时,才终止循环。
.WHILE 1 .REPEAT

.BREAK .IF condition


.BREAK .IF condition

ENDW .UNTIL 0

对于以上二个循环,如果没有指令来终止循环的话,它们都将进入死循环状态,但如果在该层循环体内,存在伪指令“.BREAK .IF condition”的话,那么,当逻辑表达式condition为真时,该循环就会被终止了。

(2)、循环继续伪指令

.CONTINUE
.CONTINUE .IF condition

标签:汇编,8086,16,bx,mov,seg,指令,ax,data
From: https://blog.csdn.net/MrXiao95/article/details/144804145

相关文章

  • 闲着没事,用STC12C5616AD制作一个74hc595测试仪
    手头有些特别廉价的直插74hc595,怕这些595因为廉价而质量不过关,因而萌发了制作一个测试仪的想法。用测试仪先对595进行测试,功能正常了,再接入电路应用。该测试仪能自动向595写入数据,再读出输出数据进行比对,如果读出的并口数据与串行写入的数据不同,说明该IC损坏或根本不是595。下......
  • Sublime Text 4 4169 下载及安装教程
    不得不说sublime是轻量化IDE性能王者,比vscode要快不少,不过vscode如今胜在生态。下面正式开始pojie教程! 补丁已经放到网盘了,需要的自取。download:SublimeText44169 首先x64dbg载入sublime_text.exe主程序,shift+F9跑起来 先找个最明显的点入手,例如点击帮助->关于......
  • [4430] 16 无包构建:盘点那些 No-bundle 的构建方案
    上节课我们讨论了Webpack的最新版本Webpack5所带来的提效新功能。思考题是Webpack5中的持久化缓存究竟会影响哪些构建环节呢?通过对compiler.cache.hook.get的追踪不难发现:持久化缓存一共影响下面这些环节与内置的插件:编译模块:ResolverCachePlugin、Compilation/modu......
  • 8086汇编(16位汇编)学习笔记08.函数
    https://bpsend.net/thread-138-1-2.html 函数结构函数结构的演变函数的结构并不是随随便便就出来的而是解决了很多问题之后,大家统一认为那个结构是最好的一种方式例如:模拟函数实现2个数相加不用函数实现两个数相加;这是栈段stacksegmentstackdb512dup(0)stack......
  • 416_前端工程化精讲
    416_前端工程化精讲//合并文档dsscript4357||已发布||开篇词|建立上帝视角,全面系统掌握前端效率工程化||d6b0ec03a4374536a361909923c61bee从事前端开发十余年曾先后在多家大型互联网公司从事前端架构工作讲师:李思嘉贝壳找房前端架构组任资深工程师,专注于前......
  • 打卡信奥刷题(500)用C++信奥P6496[普及组/提高] [COCI2016-2017#2] Nizin
    [COCI2016-2017#2]Nizin题目描述设AAA是一个含有nnn个元素的......
  • 616. Add Bold Tag in String
    Youaregivenastring s andanarrayofstrings words.Youshouldaddaclosedpairofboldtag <b> and </b> towrapthesubstringsin s thatexistin words.Iftwosuchsubstringsoverlap,youshouldwrapthemtogetherwithonlyonepairof......
  • java中各种字符编码通过字节向16进制的互转:UTF8|GBK|unicode 字符串<=>字节<=>16进制字符
    文章目录引言I16进制、字节、编码字符之间的转换前提16进制格式字符串‌16进制格式字符串的应用场景转换原理转换流程:字符串<=>字节<=>16进制java中编码的转换APIII其他例子TCP协议字段编码基于netty实现TCP的编码设置将16进制字符串转换为字符串......
  • 《计算机组成及汇编语言原理》阅读笔记:p121-p122
    《计算机组成及汇编语言原理》学习第8天,p121-p122总结,总计2页。一、技术总结1.memory优化(1)cachememoryremoveblankfrom"Mostcomputerssupporttwodifferentkinds(levels)ofcache:levelone(L1)cacheisbuiltintotheCPUchipitselfandrunsatCPU......
  • 汇编语言期末复习
    开始时间 2024-12-27 21:44:19结束时间 微处理器的结构和工作模式第二章8086CPU内部结构右总线接口单元(BIU)和指令执行单元(EU)两大部分组成。总线接口部件BIU是8086CPU与外部存储器及I/O端口之间交换数据的接口电路,它负责从内存指定单元中取出指令,送到6字节指令队列中......