用C语言的思维写汇编

【&】汇编代码模板

在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进制作为中间人。

还有需要注意的是,我们要做到的是显示出:其他进制的数字,但因为在内存调试,只有四个格子,根本放不下这么长的数,所以我们需要用打印字符的方法进行显示。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值