“段地址×16+偏移地址=物理地址”
CPU对内存进行段划分,段地址指定是内存中的一块区域,而改变偏移地址可以实现操作这块内存里的内容
在内存中指令和数据没有差别,都是二进制信息,cpu将CS:IP指向的内存视为指令
向内存中写入指令
查看刚刚我们写入的指令
ds段地址寄存器
1 | mov bx, 1000H |
这段代码相当于将1000:0的数据传送到ax寄存器
栈
==SS:SP永远指向栈顶元素==
1 | push ax |
相当于
1 | sub SP, 2 |
1 | pop ax |
相当于
1 | add SP, 2 |

标志位寄存器
运算或逻辑指令影响标志位,传送指令不影响
zf与cf

Loop
CPU在执行loop时进行两步操作:
- cx = cx - 1
- 判断cx的值,如果不为0,则转移到标号处执行程序,如果为零,则继续向下
等差求和
在c++中
1 | int num = 0; |
在汇编中则用loop代替循环
1 | assume cs:codesg |

在debug中查看,代码先执行一遍s代码,然后执行loop,相当于c++中的do…while()
call和ret
在c++中函数的目的是可以重复调用某段代码,在汇编中使用call和ret可以达到相同的效果
1 | assume cs:codesg |

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


代码段,数据段,栈段,dup指令
1 | assume cs:codesg |

观察红色方框,发现汇编指令与源代码不符,这样因为数据与指令混在一起,而在内存中数据与指令都是以机械码存储,CPU无法分辨数据与指令,而这时需要用到数据段data
1 | assume cs:codesg, ds:data, ss:stack |


如图所示,将数据放在数据段中后,不影响汇编指令
注意代码段,数据段,栈段避免相互影响,每个段都会占有n个段内存
数组
1 | assume cs:codesg, ds:data, ss:stack |
汇编中的数组与c++类似,不过汇编中的数组偏移的单位是字节
查看数据段的短地址

实战
打印helloworld

字符串转大写

ASCII 字符编码原理
在 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 位不同。
因此,通过清除(置 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 。。。