【&】汇编代码模板
在C语言中:
;//常量数据
;//函数
int main{
//逻辑代码和运行中的变量数据
return 0;
}
在汇编中:
data segment
;//常量数据
data ends
code segment
assume cs:code,ds:data
main:
;//逻辑代码和运行中变量数据
mov ax,4c00h
int 21h
;//函数
code ends
end main
【&】定义常量
c语言中:
const int a=12
在汇编中:
数据定义在data段。
假如要访问data的数据:
data segment
a dw 12
data ends
...
mov ax,data
mov ds ax
mov ax,ds:[a]
之后使用ds:[var_name]即可
【&】 定义变量
假如在代码段(cs)里面,我们用offset来对地址访问。如下,我们定义一个自变量a=12,b=23,并计算a+b,把结果存到变量x中。
c语言的写法:
void main(){
int a=12,b=23;
int x=a+b;
}
汇编写法:
code segment
assume cs:code
main:
a dw 12 ;//定义a变量 int a=12
b dw 23 ;//定义b变量 int b=23
x dw 0 ;//定义x变量 int x=0
mov si,offset a
mov di,offset b
mov bx,offset x
mov ax,cs:[si]
add ax,cs:[di]
mov cs:[bx],ax ;//x=a+b
mov ax,4c00h;//return 0
int 21h
code ends
end main
【&】写函数
完成函数任务需要注意的是堆栈进出的问题,注意两个问题:(1)保留现场(2)返回修改数据
保留现场是因为我们在执行函数段的时候必然会对寄存器进行修改,而计算机的寄存器就这么多,所以我们需要对执行函数之前的数据进行保存现场。
传参:
一般来说,我们会使用ax寄存器作为数据的返回和传入,我们优先使用通用寄存器作为数据返回的载体。
返回用 ret 指令,相当于return的意思。
【例子】
假如我们现在要完成以下C代码:
int func(int a,int b){
return a+b;
}
void main(){
int a=12,b=23;
int x=func(a,b);
}
汇编代码:
code segment
assume cs:code
main:
a dw 2
b dw 3
mov si,offset a
mov di,offset b
mov ax,cs:[si];ax=a
mov dx,cs:[di];dx=b
call func ;//调用func函数
x db 0 ;// int x=0
mov si,offset x
mov cs:[si],ax ;//x=func(a,b)
mov ax,4c00h
int 21h
;########### Functions ################
func:
add ax,dx
ret
code ends
end main
【&】正负数
在汇编里面,是不存在有无符号数的问题的。
- 第一个,有无符号数是c语言里面的概念,设置无符号数的本意是拓展计算的范围;
- 第二个,汇编里面只有一种计数方式,递增计数,满则清零。
首先,我们假设在16位计算机上,我们定义一个寄存器最大能承载的数据是:dw类型,而也就是ffff
。此时的ffff
他是一个数,那你说这个是负数还是正数呢?
答案是你既可以把他看作正数也可以看作负数。
????(小朋友你是否有很多问号)
而你把他看成正数还是负数,取决于你当前的运算需求。
比如说,现在我们要计算:-2+1=?(那这很明显是有符号数的运算咯~)
那么,你在汇编定义:
a dw -2
查看内存的数据是fffe
如果你把他和2相加,得到的数据是:ffff
也就是-1。
但你说,好,接下来,我把他看成无符号数来运算,那实际上直接拿的是ffff进行运算。
无论你是加还是减,乘还是除法,当前的这个数是正数还是负数,完全取决于你本身在脑子里面定义的逻辑是:当前是有符号数的算术还是无符号数的算术。
要想保证我们得到的结果是正常的,就必须保证不要越位溢出了,例如,你说,现在我要拿一个ffff+ffff,而且还是无符号数的运算,用add指令那肯定是算不出来的,因为你已经溢出了,除非你使用32位的运算指令。
牢牢记住汇编数据正负数的原则:正常计数,满则清零,有无符号看需求
【&】加减乘除
四则运算需要注意是之前说的有无符号的问题,需要根据我们的需求对数进行有无符号的定义。
除法
字节除法指令:div cs:[si]
al=ax/cs:[si]
ah是余数
字除法指令:div cs:[si]
ax=ax/cs:[si]
dx是余数存放
需要注意的是,如果我们执行字除法指令,dx必须要先清零!!
乘法
字节乘法指令:mul cs:[si]
ax=al*cs:[si]
字乘法指令:mul cs:[si]
dxax=ax * cs:[si]
这里需要注意是乘除法的范围问题,除法,我们可以想象,当al存放最大的无符号数是ff,也就是255,ah同理。
不要越界即可。
【&】打印字符和数字
首先你需要明白,我们在面板里面打印出来的字符只有在ascii表上的字符,假如我们需要打印某个数字,我们就需要实现逐位打印。
【&】进制转换(假)
为什么我们说进制转换的题目“假”呢?
首先,无论我们在需求上怎么要求进制转换,存放在内存和寄存器的数据都是实实在在的真值。我们需要牢牢记住这样一个原则:存的是真值!(运算的也是真值)
我们经常遇到一些需求说要进行进制转换,实际上,所谓的进制转换是 “显示出来” 的进制转换,也就是我们肉眼所见的数字,他不是真的。
在C语言中,我们已经掌握了一些进制假转换的算法,我们只需要掌握的是:16进制转n进制,n进制转16进制。
为啥用16进制作为掌握的标准呢?
因为存的是真值,我们在内存里面调试看到的是16进制的数据,所以说,方便拿16进制作为中间人。
还有需要注意的是,我们要做到的是显示出:其他进制的数字,但因为在内存调试,只有四个格子,根本放不下这么长的数,所以我们需要用打印字符的方法进行显示。