https://space.bilibili.com/362535177,感谢此位up主的汇编教程,获益匪浅

“段地址×16+偏移地址=物理地址”

CPU对内存进行段划分,段地址指定是内存中的一块区域,而改变偏移地址可以实现操作这块内存里的内容
在内存中指令和数据没有差别,都是二进制信息,cpu将CS:IP指向的内存视为指令

向内存中写入指令
在这里插入图片描述
查看刚刚我们写入的指令
在这里插入图片描述

ds段地址寄存器

1
2
3
mov bx, 1000H
mov ds, bx
mov al, [0]

这段代码相当于将1000:0的数据传送到ax寄存器

==SS:SP永远指向栈顶元素==
在这里插入图片描述

1
push ax 

相当于

1
2
sub SP, 2
mov SS:SP, ax ;将ax的数据转移到SS:SP所指的内存, 大概是这个意思,实际是并没有这个指令

1
pop ax

相当于

1
2
add SP, 2
mov ax, SS:SP ;同上

在这里插入图片描述

标志位寄存器

运算或逻辑指令影响标志位,传送指令不影响

zf与cf

在这里插入图片描述

Loop

CPU在执行loop时进行两步操作:

  • cx = cx - 1
  • 判断cx的值,如果不为0,则转移到标号处执行程序,如果为零,则继续向下

等差求和

在c++中

1
2
3
4
5
6
7
int num = 0;
int sum = 0;
for (int i = 0; i < 100; i++) {
num++;
sum += num;
}
return sum;

在汇编中则用loop代替循环

1
2
3
4
5
6
7
8
9
10
11
assume cs:codesg
codesg segment
mov ax, 0 ;相当于num
mov bx, 0 ;相当于sum
mov cx, 100
s: inc ax
add bx, ax
loop s
int 21H
codesg ends
end

在这里插入图片描述
在debug中查看,代码先执行一遍s代码,然后执行loop,相当于c++中的do…while()

call和ret

在c++中函数的目的是可以重复调用某段代码,在汇编中使用call和ret可以达到相同的效果

1
2
3
4
5
6
7
8
9
10
11
assume cs:codesg
codesg segment
mov ax, 3
mov cx, 11
call s ;调用函数s
int 21H
s: add ax, ax
loop s
ret
codesg ends
end

在这里插入图片描述
在图中在执行cal指令时会跳转到000B也就是函数s开始的位置,那执行完函数如何返回?
实际上在执行cal指令会将cal的下一个指令压入栈,在执行ret的指令时,会将栈顶的数据pop给IP
在这里插入图片描述
观察栈帧,此时里面没有数据
在这里插入图片描述
第一张图片的int 21H的地址是0009,观察上图的栈帧,发现此时的栈顶数据正是0009

call far ptr与retf

在这里插入图片描述
在这里插入图片描述

代码段,数据段,栈段,dup指令

1
2
3
4
5
6
7
8
9
10
assume cs:codesg
codesg segment
dw 123H, 456H, 789H, 0abcH, 0defH
mov ax, 2
mov cx, 11
s: add ax, ax
loop s
int 21H
codesg ends
end

在这里插入图片描述
观察红色方框,发现汇编指令与源代码不符,这样因为数据与指令混在一起,而在内存中数据指令都是以机械码存储,CPU无法分辨数据指令,而这时需要用到数据段data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
assume cs:codesg, ds:data, ss:stack

data segment
db 'hello,world'
dw 123H, 456H, 789H, 0abcH, 0defH
data ends

stack segment
db 10 dup(0)
stack ends

codesg segment
start:
mov ax, 2
mov cx, 11
s: add ax, ax
loop s
int 21H
codesg ends
end start

在这里插入图片描述
在这里插入图片描述
如图所示,将数据放在数据段中后,不影响汇编指令
注意代码段,数据段,栈段避免相互影响,每个段都会占有n个段内存

数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
assume cs:codesg, ds:data, ss:stack

data segment
arr db 10h, 20h, 30h, 40h, 50h ;数组
arr2 db 'hello world' ;数组
data ends

stack segment
db 10 dup(0)
stack ends

codesg segment
start:
mov ax, data
mov ds, ax ;将数据段的地址传送到ds
mov al, arr2[3]
mov bx, data
int 21H
codesg ends
end start

汇编中的数组与c++类似,不过汇编中的数组偏移的单位是字节

查看数据段的短地址
在这里插入图片描述
在这里插入图片描述

实战

打印helloworld

在这里插入图片描述

字符串转大写

在这里插入图片描述
ASCII 字符编码原理

  1. 在 ASCII 表中,小写字母和大写字母的编码有固定的差异:

    • 小写字母 ( ‘a’ ) 到 ( ‘z’ ) 的 ASCII 范围是 ( 97 (0x61) ) 到 ( 122 (0x7A) )。
    • 大写字母 ( ‘A’ ) 到 ( ‘Z’ ) 的 ASCII 范围是 ( 65 (0x41) ) 到 ( 90 (0x5A) )。
    • 小写字母与大写字母的差异是二进制第 6 位(从右数,最低位是第 1 位),即小写字母的第 6 位为 ( 1 ),而大写字母的第 6 位为 ( 0 )。

    举例:

    1
    2
    'a' = 0110 0001
    'A' = 0100 0001

    仅第 6 位不同。

  2. 因此,通过清除(置 0)第 6 位,可以将小写字母转换为大写字母。

c语言反汇编

放指抬压
在这里插入图片描述

  • 放:将ebp(调用此函数函数的栈帧ebp)压入栈空间
  • 指:将ebp指向压入栈空间的ebp
  • 抬:ebp减小,开辟一段空间
  • 压:将edi等寄存器压入栈,保留环境

指令

在这里插入图片描述

伪指令与汇编指令

  • 伪指令: 是由编译器执行的指令
  • 汇编指令:可以被翻译成机械码,最终被CPU运行

Debug基本指令

在这里插入图片描述

  • go

汇编指令

在这里插入图片描述

  • mul
  • div
  • and
  • or
  • shl
  • shr
  • inc
  • dec
  • xchg
  • reg
  • int
  • push
  • pop
  • adc
  • cmp
  • loop
  • cal
  • ret
  • dup
  • offset
  • jmp,jmp short 。。。