【汇编语言】8086、x86-32和C语言【赋值语句 和 数组】的对比学习(王爽学习笔记:5.8段前缀的使用)

0 前言

这里给出两种思路,都比王爽老师书上的做法要简单高效,事实上,理解指令的本质,就能达到灵活应用,这样才能打破规则

题目:将内存ffff:0 - ffff:b的数据,复制到内存ffff:10 - ffff:1b中

备注:使用8086汇编语言

本篇的核心是:分别使用8086、x86-32和C语言,理解内存空间的复制

1 思路一:使用push、pop指令

push,pop指令的本质,是内存传送指令,它也是送数据的。

例如pop DS:[EA]本质是mov DS:[EA],SS:[SP]

; 思路一:使用push,pop内存转移指令,注意是字型数据,2个2个搬运
assume cs:code
code segment
start:
	; DS:[bx]指向0:200
	mov ax,0
	mov ds,ax
	mov bx,0200h
	
	; 设置栈顶
	mov ax,0ffffh
	mov ss,ax
	mov sp,0
	
	; 设置循环
	mov cx,6
	s:
		pop [bx]
		add bx,2  ; 一次copy一个字
		loop s
		
	mov ax,04c00h
	int 021h
code ends
end start

2 思路二:使用段前缀

完全没有必要一个字节一个字节传送,这样需要字节扩展为字再使用,效率低下。

; 思路二:使用段前缀
assume cs:code
code segment

start:
	mov ax,0ffffh
	mov ds,ax
	mov ss,ax
	
	mov bx,0
	mov cx,6
	s: 
		mov dx,ds:[bx]
		mov ss:[bx+10h],dx
		add bx,2
		loop s
		
	mov ax,04c00h
	int 021h
code ends
end start

3 结合C语言和x86-32汇编语言

这个题目,本质上对应于C语言的基本模型:赋值语句,例如int a = b;

int a = 2;
int b;
b = a;

对应汇编语言

int a = 2;
mov dword ptr [a],2

int b
b = a;
mov eax,dword ptr [a]
mov dword ptr [b],eax

这里也可以看出int b;变量声明,是不会生成汇编代码的,它的本质就是给某个内存段做个标记,叫b,且它占连续的4个字节

4 第3部分的扩展:连续内存空间的copy

先来看一个基本数组

int a[10] = { 1,23,4,4,5,6,77,0 };

对应的汇编

00184198  mov         dword ptr [a],1  
0018419F  mov         dword ptr [ebp-28h],17h  
001841A6  mov         dword ptr [ebp-24h],4  
001841AD  mov         dword ptr [ebp-20h],4  
001841B4  mov         dword ptr [ebp-1Ch],5  
001841BB  mov         dword ptr [ebp-18h],6  
001841C2  mov         dword ptr [ebp-14h],4Dh  
001841C9  mov         dword ptr [ebp-10h],0  
001841D0  xor         eax,eax  
001841D2  mov         dword ptr [ebp-0Ch],eax  
001841D5  mov         dword ptr [ebp-8],eax 

这里有一个值得注意的地方,就是寄存器的清零,这里使用了xor eax,eax,一个数跟自己异或,再赋值给自己,必然是0,这个用法比较新奇。当然也可以使用基本语句mov eax,0

另外,你可以知道

  1. 数组被分配了一段连续的内存空间,共40字节
  2. 地址顺序与数组标号顺序一致,都是从小到大
  3. 没有被赋值的,默认赋值为0

如果想要将整个数组的内容,复制到另外一个数组int b[10]怎么办?

最容易想到的做法是,直接循环递增复制

int a[10] = { 1,23,4,4,5,6,77,0 };

int b[10];
for (int i = 0; i < 10; i++) {
	b[i] = a[i];
}

对应的汇编语言

     1: 	for (int i = 0; i < 10; i++) {
00DB4D21  mov         dword ptr [ebp-78h],0  
00DB4D28  jmp         00DB4D33  
00DB4D2A  mov         eax,dword ptr [ebp-78h]  
00DB4D2D  add         eax,1  
00DB4D30  mov         dword ptr [ebp-78h],eax  
00DB4D33  cmp         dword ptr [ebp-78h],0Ah  
00DB4D37  jge         00DB4D49  
     2: 		b[i] = a[i];
00DB4D39  mov         eax,dword ptr [ebp-78h]  
00DB4D3C  mov         ecx,dword ptr [ebp-78h]  
     3: 		b[i] = a[i];
00DB4D3F  mov         edx,dword ptr [ebp+ecx*4-30h]  
00DB4D43  mov         dword ptr [ebp+eax*4-6Ch],edx  
     4: 	}
00DB4D47  jmp         00DB4D2A

这种拷贝方式,就是一个个拷贝,很容易想到,但是在C语言中,这一点都不酷,不过这种做法与最开始8086汇编的思路是一致的,一点点转移过去,应该有更酷的内容被使用。

此外,应该了解小知识点是 【寻址方式】,对于语句mov edx,dword ptr [ebp+ecx*4-30h]中的[ebp+ecx*4-30h],地址形成的方式是 ebp + ecx*常数 + 常数

更酷的方式是memcpy函数(memory copy),也就是内存复制。

int a[10] = { 1,23,4,4,5,6,77,0 };
int b[10];
memcpy(&b, &a,sizeof(a));

这样,就能够直接将整个内存空间拷贝到另外一段内存空间了,不过,这种做法其实就是直接使用封装的函数,本质还是一点点拷贝过去。但是对于高级语言来说,应该更多地使用已经封装好的常用函数,以提高效率。

对于memcoy的用法,简单说明,(1,2,3)

  • 1放的是目标的内存地址空间的首地址,这里是&b
  • 2放的是源内存地址空间的首地址,这里是&a
  • 3放的是需要拷贝过去地址空间的大小,这里是sizeof(a),也就是40个字节
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XV_

感谢您的认可,我会继续努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值