指令的执行
指令的长度是可以是多个字节
- cpu从cs:ip所指向的内存单元中读取指令,存放到指令缓存器中
- ip=ip+所读指令的长度,从而指向下一条指令
- 执行指令缓存器的内容,回到下一个步骤
这个顺序是很重要的,为什么要使用2和3的顺序哪,这是因为当我们调用一个函数时使用这种方式很好用
我们可以得出结论,数据和指令是没有差别的,当使用读取cs:ip指向的地址,cpu便将其当成指令执行
debug使用
-u 表示显示出当前位置的代码
-u 段地址:偏移地址 显示指定位置的代码
-d 表示显示当前位置的数据
-u 段地址:偏移地址 显示指定位置的数据
-a 表示直接在当前位置写入指令
-a 段地址:偏移地址 表示在指定的位置写入指令
-r 表示显示当前寄存器的内容
-r 寄存器 然后显示指定寄存器的内容在下一行写入 :2000表示将这个寄存器的内容设置成2000
-e 段地址:偏移地址 可以改写内存的内容
jmp指令
jmp是转移指令是jump的简写,表示跳跃的意思。
指令的格式: jmp 2000:0表示将cs设置成2000,将ip设置成0,因此这个指令能够改变指令执行的位置
cs和ip寄存器是不能够使用mov来进行更改的,只能使用jmp来改变
比如 mov cs,1000是错误的
还可以使用
jmp 寄存器
的方式来更改ip的内容
call 函数名 表示函数的开始
这个指令也是一个转移指令,但是这个指令和jmp还是有区别的,因为call指令会保存一个当前的执行到的位置保存在内存中。
ret 这个指令是在函数的结束的一个指令,他的操作是将call指令执行时保存的那个地址还原回来。
上面两个的作用实现了函数的调用
我们可以使用
-e 2000:0
输入数据
-r cs
:2000
-r ip
:0
表示改变cs:ip
现在我们便可以执行了
问题:
call指令将ip这个偏移地址值存放到那里去了 ret可以拿回
小端法 表示高位在高地址 低位在低地址
ds段地址寄存器
mov al,ds:[0]
mov al,ds:[1]
mov ax,ds:[0]
mov ax,ds:[1]
mov ds:[0],ax
mov ds:[1],ax
mov ds:[0],al
mov ds:[1],al
mov ax,[1]
字节型数据和自行数据在内存中的存放
使用小端法进行存放
ds段地址寄存器 数据段寄存器
cs和指令有关
栈 是一段连续的存储单元
入栈和出栈的数据长度都是16位的,因此push和pop的对象都是16位的
栈顶标记 在入栈时决定了押入栈的数据
栈顶标记是内存地址 内存地址是使用段地址和偏移地址表示的
在8086cpu中 将段地址寄存器ss和偏移地址寄存器sp所组合的内存地址当成栈顶标记
因此ss和sp只能确定一个地址 栈顶地址
push的工作原理表示将数据入栈,然后sp=sp-2
pop的工作原理表示将数据出栈,然后sp=sp+2
使用 d ss:偏移地址可以显示栈的数据
在入栈时会将寄存器的值放入栈中
我们可以控制栈的位置和大小
比如我们更改ss的值来设置栈的位置 设置sp的大小来决定栈的大小,这样便可以在sp处入栈,直到ss*10h处
所以说我们可以随便设置一个栈的地址
栈顶的越界问题
当数据的存储满时,还继续push变会栈的越界,会破坏其他的数据
pop和push只影响sp的值
sp的变化的范围 0~ffffH
因此栈的大小是有范围的 如果超过这个返回会覆盖栈的内容,因为ss是不变的,sp会变,sp从某个值一直减小到0,然后又从ffffH继续减小,会覆盖原来存入栈的内容
如果我们需要使用函数需要设置ss和sp来设置一个栈,然后使用call指令,这个call指令有两个作用,一个是保存当前的ip值到栈的最高位置中,另一个是设置ip的新值来获取函数的执行地址。
栈的作用便是临时性保存数据,这是因为寄存器是很少的,当执行另外一个功能时,我们需要临时保存数据到内存中,否则当其他代码使用寄存器时会覆盖掉寄存器的内容。
栈的作用