汇编语言的学习

简介: 本文详细介绍了在DOSBox中学习汇编语言的基础知识,包括寄存器的使用、数据和指令的选取、栈的操作、段地址的计算以及如何编写和执行简单的汇编程序。

寄存器

在DOSBox里面有ax,bx,cx,dx,sp,ip,ds,之类的,如下图

寄存器的种类

可以分为数据类和指令类

AX(AH、AL):累加器

BX(BH、BL):基址寄存器

CX(CH、CL):计数寄存器

DX(DH、DL):数据寄存器 //不过这些都可以修改,一般就数据和指令。

指令

指令的选择是通过cs:ip来选择的。

其中cs代表段地址,ip代表偏移地址

选择该地址内容的数据做为指令。例如:

数据

数据的选择是通过ds:偏移量来确定的,例如:

这里我修改了ds的值,让ds指向1000的地址,在将ax赋值1000:0000地址的值

从这里就可以知道了,数据的选择是ds决定的。

段地址*10H +偏移地址=物理地址

这里可以看到,这两块的地址是一模一样的,类似于:2000+2000和4000的内容是一模一样的,地址含义也一样

我一般认为是绝对地址和相对地址。就比如说这个,1*10H+0=10H,所以绝对地址是0000:0010,而0001就是段地址,0001:0000就是相对地址,有什么问题可以发出来。

call指令

call指令的作用,就是跳转,但是和jmp的区别是会将下一条指令的ip存到栈中

后面使用ret指令回来(将ip修改回来)

这里是运行了call指令,原先ip=100,后面栈中存放下一条指令也就是103。

这里用了ret,将ip修改回来了(通过栈)


-

汇编里面的栈是通过ss:sp来指向的,用这里面的内存来存储数据

栈是先进后出,每次加进来的都要在标记的前面。

在这里面的内存形式0000:0000------->ffff:ffff ,所以每次入栈(push)sp=sp-2,而每次出栈就是(pop)sp=sp+2

栈的最大内存是sp=0时,因为sp=0-2=fffh,所以sp=0时栈内存最大

栈的内存表示,sp的起始到sp被我修改的值,其实是人为的认为,最常见认为sp的起始为0,sp的终止是10h,所以栈内存为10H

具体格式:push ax //是将ax里面的值存入ss:sp内存中

pop bx //是将栈里面的内容存入到bx寄存器中

类似的。

psp区

开始的256个字节是psp区,其作用是为了程序与系统进行通信的

ds是取数据的,ds:0的数据并不是我写的程序的数据,一直到ds:0100才是,所以开始的256个字节是系统与程序进行通信的

一个标准的asm(汇编)文件格式

assume cs:code
​
code segment
​
        mov ax,2000H   ;在汇编语言中,;代表注释,mov代表赋值,add代表相加,pop出栈,push入栈,sub相减,jmp跳转,call
        mov ss,ax      ;,号右边给左边,这个,号类似于等号
        mov sp,0       ;等等
        add sp,10H     
        pop ax
        pop bx          
        push ax
        push bx   ;交换ax,bx数据
        pop ax
        pop bx
                  ;inc为增加的英文,inc bx,就是将bx加1,为了节约内存
​
        mov ax,4C00H  ;程序返回
        int 21H
​
code ends
​
end

loop循环以及用jmp实现类型loop

loop比jmp多了一个次数操作,用cx来保存次数

jmp可以实现跳转

-p 可以直接执行完loop指令

-g 类似于go 后面要加地址

loop也可以实现,但是loop需要注意的是cx=1,和cx=0的情况

cx=0时,会出现溢出。

当cx=1时,可以看出并没有循环,原因是走了一遍就算循环了一次,当cx=0时跳出循环,如果还没有走cx已经为0了,cx-1=FFFF,就要循环FFFF次。

用汇编指令写234*145

assume cs:code
code segment
​
​
            mov ax,0
            mov cx,145
addnumber:  add ax,234      ;jmp也是和loop一个格式,除开cx次数
            loop addnumber

            mov ax,4C00H
            int 21H
​
code ends
​
end

debug的缺陷:有英文字母开头时,前面要加0

比如:mov ax,0ffffH

不加H时表示十进制。

通过es和ds数据寄存器来交换数据实操

assume cs:code
code segment
​
​
            mov ax,0fffH
            mov ds,ax
            mov ax,2000H
            mov es,ax
​
            mov cx,10H
            mov bx,0
adderten:   mov al,ds:[bx]
            mov es:[bx],al  ;es:[bx]是一个字节数据类型,不是字型数据类型
            inc bx
            loop adderten
​
​
mov ax,4C00H
int 21H
​
code ends
​
end

通过栈来复制两个地方的数据

assume cs:code
code segment
            mov bx,0
            mov cx,10H
adderten:   mov ax,0fffH
            mov ds,ax
            mov ax,0
            mov al,ds:[bx]
            push ax
            mov ax,2000H
            mov ds,ax
            pop ds:[bx]
            inc bx
            loop adderten
​
​
mov ax,4C00H
int 21H
​
code ends
​
end

dw 操作数据

assume cs:code
code segment
​
      dw 1,2,3,4,5,6,7,8,9
start:
       mov ax,0
       mov bx,0
addax: add ax,cs:[bx]   ;start 指定操作开始的位置
       add bx,2         ;不用start在开头用jmp指令也行
       loop addax    
​
mov ax,4C00H
int 21H
​
code ends
​
end  start

dw和栈联用

assume cs:code
code segment
​
​
      dw 1122H,2233H,3344H,4455H,5566H,6677H,7788H,8899H,9900H
      dw 0,0,0,0,0,0,0,0
      dw 0,0,0,0,0,0,0,0
start:
         mov ax,cs
         mov ss,ax
         mov sp,32H     ;栈内存是看字节形数据,所以应该是32H
         mov bx,0
         mov cx,9
addax:   push cs:[bx]
         add bx,2
         loop addax
​
mov ax,4C00H
int 21H
​
code ends
​
end  start

数据段,指令段,stack段

这样写可能会出一个bug,就是设置sp的大小就一定要和栈段一致,不然就会执行不知道什么的指令,那个时候就是严重型bug

assume cs:code,ds:data,ss:stack
data segment
      dw 1122H,2233H,3344H,4455H,5566H,6677H,7788H,8899H,9900H
​
data ends
​
stack segment
      dw 0,0,0,0,0,0,0,0
      dw 0,0,0,0,0,0,0,0
stack ends
​
code segment
​
start:
      mov ax,stack        
      mov ss,ax           ;设置栈
      mov sp,32           ;如果这样写了,设置栈的大小就一定要和栈段里面的要一致
      mov ax,data         
      mov ds,ax           ;设置数据段
      mov bx,0            ;这样做就会将ds寄存器当作数据,ss:sp数据当作栈。
      mov cx,9            
addax:  push data:[bx]
       add bx,2
      loop addax
​
mov ax,4C00H
int 21H
​
code ends
​
end  start
​

段的位置

第一段一般是数据,第二段一般是栈,第三段则是指令

第一和第二段可以换位置,但是第三段不能换,涉及到数据覆盖问题

数据段位置:

栈段位置:

指令段:

段的空间大小

就是16的倍数,如果比如9个字节长度,大小就是16个字节,如果说是23个字节长度,大小就是32个字节。

向大号取整。

比如说这个例子:就是数据是9个字型性长度,所以用了32个字节型长度。

段的练习1:将两个数据段的数据相加,放到另外一个段中

assume cs:code
a segment
      db 1,2,3,4,5,6,7,8
​
a ends
​
b segment
      db 1,2,3,4,5,6,7,8     ;因为数据段寄存器不够了,所以先用栈保存一下位置,然后直接修改es寄存器将es寄存器改成c段那边,然                              ;后赋值,后面pop掉es,就行了
b ends

c segment
      db 0,0,0,0,0,0,0,0
c ends
​
​
code segment
​
start:
       mov ax,a
       mov ds,ax
       mov cx,8
       mov ax,b
       mov es,ax
       mov bx,0
       mov ax,0
addax: push es
       mov ax,ds:[bx]
       add ax,es:[bx]
       mov dx,c
       mov es,dx
       mov es:[bx],ax
       inc bx
       pop es
       loop addax

       mov ax,4C00H
       int 21H
​
      code ends
​
       end  start
​

段的练习2:将a段中的前8个字型数据,逆序复制到b段中

assume cs:code
a segment
      dW 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0FH,0FFH
​
a ends
​
b segment
      dW 0,0,0,0,0,0,0,0
b ends
​
code segment
​
start: mov ax,b
       mov ss,ax
       mov sp,16
       mov ax,a
       mov ds,ax
       mov bx,0
       mov cx,8
adder: push ds:[bx]
       add bx,2
       loop adder
       mov ax,4C00H
       int 21H
​
      code ends
​
       end  start
​

bx,si,di都为偏移地址寄存器

assume cs:code
a segment
      dW 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0FH,0FFH
​
a ends
​
b segment
      dW 0,0,0,0,0,0,0,0
b ends
​
code segment
​
start: mov ax,a
       mov ds,ax
       mov si,1
       mov di,2
       mov bx,0          
       mov ax,ds:[bx+si] ;唯一的缺点就是不能用减法
       add ax,ds:[di]
      code ends
end  start

and,or运算符

assume cs:code
a segment
      dW 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0FH,0FFH
​
a ends
​
b segment
      dW 0,0,0,0,0,0,0,0
b ends
​
code segment
​
start: mov ax,00001111B
       and ax,11110000B
      code ends
end  start
​
assume cs:code
a segment
      dW 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0FH,0FFH
​
a ends
​
b segment
      dW 0,0,0,0,0,0,0,0
b ends
​
code segment
​
start: mov ax,00001111B
       or ax,11110000B
       mov ax,'a'
       mov bx,'b'
      code ends
end  start

字符

同个字母的大写字母比小写字母要小32

将数据段nihao中的i变成大写I

assume cs:code
a segment
      db 'nihao,I am you '
​
a ends
​
b segment
      dW 0,0,0,0,0,0,0,0
b ends
​
code segment
​
start: mov ax,a
       mov ds,ax
       mov bx,1
       mov al,ds:[bx]
       and  al,11011111B  ;注意不能在数据段进行and or操作
       mov ds:[bx],al
       mov ax,4C00H
       int 21H
      code ends
end  start

将数据段中的所有数据变成大写

assume cs:code
a segment
      db 'nihao,I am you '
​
a ends
​
b segment
      dW 0,0,0,0,0,0,0,0
b ends
​
code segment
​
start: mov ax,a
       mov ds,ax
       mov bx,0
       mov cx,14
adder: mov al,ds:[bx]
       and  al,11011111B
       mov ds:[bx],al
       inc bx
       loop adder
       mov ax,4C00H
       int 21H
      code ends
end  start
​

使用si和di偏移地址寄存器

后面持续更新

目录
相关文章
王道408计组汇编语言部分学习总结
用于实现分支结构、循环结构的指令: cmp、 test、 jmp、 jxxx 用于实现函数调用的指令: push、pop、call、 ret 用于实现数据转移的指令: mov
460 0
|
4月前
|
存储 算法 NoSQL
天呐!汇编语言竟如此神奇,从零到精通的学习指南带你开启计算机世界神秘大门!
【8月更文挑战第31天】汇编语言是一种底层编程语言,直接与硬件交互,对于理解计算机体系结构和底层原理至关重要。尽管现代软件开发中较少使用,但学习汇编语言有助于深入了解计算机如何执行指令、管理内存和处理数据,从而优化程序性能,进行底层系统开发和调试。不同处理器有不同指令集,如 x86 和 ARM,掌握这些指令集及寄存器、内存地址等基本概念是学习汇编语言的基础。通过简单示例开始,逐步掌握复杂指令和调试工具,可以大大提高编程技能和解决问题的能力。
83 1
|
6月前
|
程序员 索引
逆向学习汇编篇:内存管理与寻址方式
逆向学习汇编篇:内存管理与寻址方式
62 0
|
7月前
|
编译器
【Bug】8086汇编学习
随笔 与汇编的灵活与底层所伴随的,是使用者极大的心智负担。 模块之间的隔离性很难控制。甚至多个子程序间的标号也不能相同,故子程序无法独立开发后直接集成。
166 5
|
7月前
汇编指令学习(寻址方式)
汇编指令学习(寻址方式)
66 0
|
7月前
汇编指令学习(LOOP)
汇编指令学习(LOOP)
99 0
|
7月前
汇编指令学习(CALL,JMP,RET)
汇编指令学习(CALL,JMP,RET)
117 0
|
7月前
|
JavaScript
汇编指令学习(JMP、JE、JS、JP,JO,JB)
汇编指令学习(JMP、JE、JS、JP,JO,JB)
561 0
|
7月前
汇编指令学习(CMP,TEST)
汇编指令学习(CMP,TEST)
154 0
|
7月前
汇编指令学习(AND,OR,XOR,NOT)
汇编指令学习(AND,OR,XOR,NOT)
118 0