更优雅的打印字符串
更优雅的打印字符串
目标:给定一个以0x00结尾的字符串在内存中的起始地址,通过调用一个函数,把整个字符串输出到屏幕上。
ds和es是段寄存器,si和di是变址寄存器
通过段寄存器DS以及源索引寄存器SI来保存字符串的起始地址,即DS:SI,而SI指向第一个字符出现的位置,取出一个字符SI就加1。通过段寄存器ES以及目标索引寄存器DI,保存写入的目标地址,也就是显存的地址,ES的值位0xb800,DI寄存器的初始值位0x0000,写入一个字节就加1, 通过循环将DS:SI指向的字符串依次取出,并写入到ES:DI指向的目标地址,直到遇到0x00结束循环
EFLAGS寄存器
第0位CF位,进位标志
第2位PF位,偶数标志位,当计算结果是偶数时,PF会被置1
第6位是ZF位,Zero Flag,零标志位,独立结果为0时,ZF会被置1
第7位是SF位,也就是符号位,比如减法结果为负值,他就会被置1
第11位是OF位,也是溢出位,当计算结果存在溢出时,它会被置为1
标志位的用法,要结合条件转移指令使用
JCC-条件转移指令
jz Jump if zero(ZF=1)
jnz Jump if not zero(ZF=0)
cmp-比较指令
cmp dest目的(reg/mem) source源(reg/mem/imm)
比较两个数,改变标志寄存器的值
section-分段
section name align=16/32 vstart=0
align:加align与不加align的区别在于,如果定义多个section,而某些section的内容不足16字节,编译器就会给你补齐到16字节,而不加align参数就没有这个效果
vstart:这个参数的用途是设置段内的偏移地址的基准地址,如果不设置这个参数,那么在编译阶段,所有的偏移地址都是按照程序头部来算的,而默认的程序头部基准地址为0x0000,如果我们使用了标号,那么标号的偏移地址,也就是汇编地址,是跟程序加载到内存的偏移地址保持一致的。在真机运行环境,我们的程序会被加载到0x7c00位置,并且段寄存器如ES,DS,SS等都默认初始化位0x0000,但是程序的起始位置却是0x7c00,这就导致程序里的标号不对了。解决办法有两种,一种是把DS,ES,SS都初始化为0x7c00,另外一种是使用vstart参数,让vstart=0x7c00,汇编地址在计算的时候会自动加上0x7c00。
call指令
call 标号
类似函数调用,call 后面跟一个标号、寄存器或者内存地址,标号的本质也是个内存地址偏移。标号的本质也是一个内存地址偏移。我们把常用的一段代码放到标号后面,形成类似函数的代码块。需要注意的是,在代码块的最后,要加一个ret指令,就是return。代码先顺序执行,遇到call指令调用代码块,遇到ret返回调用点,汇编用寄存器来保存传入传出参数。
and-与运算指令
and dest目的(reg/mem) source源(reg/mem/imm)
or-或运算指令
or dest目的(reg/mem) source源(reg/mem/imm)
or bh,0x000,通过ZF可以判断bh是否为0
not-非运算指令
not reg/mem
xor-异或运算指令
xor dest目的(reg/mem) source源(reg/mem/imm)
影响ZF标志位,也可以通过ZF判断两个数是否相等
打印字符串
1 | NUL equ 0x00 |
运行结果














