汇编学习(4)

子程序参数调用约定:
在这里插入图片描述

寄存器传参:使用方便,但可分配参数少
堆栈传参:较为复杂,但可安排足够多的局部变量。需注意进出栈的平衡

子程序设计过程中应使子程序和主程序保持某种默契,采用某一种约定。
例:在C函数目标代码中, 不保护eax、ecx和edx,保护ebx、esi、edi和ebp。

在使用乘除指令时,应看情况是否需要对edx进行处理,否则指令会出错。
在内联汇编程序过程中也应当注意寄存器的使用优先级,尤其ebp和esp尽量不要使用,否则会在涉及栈的操作时出错。

以下子程序统一使用寄存器ecx和edx传参,使用eax作为返回值

  //子程序D2Hstr
  //功能:将数据转化为十六进制字符串
  //参数:ecx 待转化数据 edx 字符串存储地址
D2Hstr:
  //初始化
  mov  ebx, ecx
  push edi
  mov  edi, edx
  mov  ecx, 8
L:
  mov  eax, 0xf0000000
  and  eax, ebx //取出高4位
  shr  eax, 28
  shl  ebx, 4
  cmp  al, 10 //判断对应十六进制是数字还是字母
  jl  Number_D2Hstr
  add  al, 7 //如果对应十六进制是字母,则多加7
Number_D2Hstr:
  add  al, 48 //转化为对应ascll码值
  stosb
  loop L
  mov  eax, 0
  stosb
  pop  edi
  ret
  //子程序D2Dstr
  //功能:将数据转化为十进制字符串
  //参数:ecx 待转化数据 edx 字符串存储地址
D2Dstr:
  //初始化
  push edi  
  push edx  
  mov  edi, edx
  mov  edx, ecx
  mov  bl, 10  //除数为10
  mov  ecx, 0
  mov  eax, edx //将待处理数分配在ax中
L1_1:
  div  bl
  inc  ecx
  mov  ah, 0
  cmp  al, 0 //判定是否处理完成
  jne  L1_1
  mov  [edi+ecx], 0
  
  mov  eax, edx //将待处理数分配在ax中
L1_2:
  div  bl
  add  ah, 48
  dec  ecx
  mov  [edi+ecx], ah
  mov  ah, 0
  cmp  al, 0 //判定是否处理完成
  jne  L1_2
  //平衡堆栈
  pop  edx
  pop  edi
  ret
  //子程序D2Bstr
  //功能:将数据转化为二进制字符串
  //参数:ecx 待转化数据 edx 字符串存储地址
D2Bstr:
  //初始化
  mov  ebx, ecx
  push edi
  mov  edi, edx
  mov  ecx, 8
  //开始转化
L3:
  mov  eax, 0x80
  and  eax, ebx //取出最高位
  mov  al, 48
  je  Z
  inc  al
Z:
  stosb
  shl  bl, 1
  loop L3
  //添加终止符
  mov  eax, 0
  stosb
  //平衡堆栈
  pop  edi
  ret
  //子程序judge_vowel
  //功能:判断元音字母
  //参数:ecx 待判定字符
  //返回值:eax 1表示是元音字母,0表示不是
judge_vowel:
  xor  eax, eax //eax置零
  cmp  cl, 'a'
  je  is_vowel
  cmp  cl, 'e'
  je  is_vowel
  cmp  cl, 'i'
  je  is_vowel
  cmp  cl, 'o'
  je  is_vowel
  cmp  cl, 'u'
  je  is_vowel
  jmp  end_judge
is_vowel:
  inc  eax  //设置返回值为1
end_judge:
  ret
  //子程序D2Ostr
  //功能:将数据转化为八进制字符串
  //参数:ecx 待转化数据 edx 字符串存储地址
D2Ostr:
  //初始化
  mov  ebx, ecx
  push edi
  mov  edi, edx
  mov  ecx, 10
  //八进制化高2位
  mov  eax, 0xc0000000
  and  eax, ebx //取出最高2位
  shr  eax, 30
  add  al, 48
  stosb
  //八进制化剩余部分
L_D2Ostr:
  mov  eax, 0x38000000
  and  eax, ebx //取出未处理部分高3位
  shr  eax, 27
  shl  ebx, 3
  add  al, 48
  stosb
  loop L_D2Ostr
  //添加终止符
  mov  eax, 0
  stosb
  //平衡堆栈
  pop  edi
  ret
  //子程序Dstr2D
  //功能:将十进制字符串转化为数据
  //参数:ecx 字符串存储地址
  //返回值:eax转化后的数据
Dstr2D:
  push ebx
  push edx
  push edi
  xor  eax, eax //eax置零
  mov  edi, 10  //乘数为10
  //开始转化
L_Dstr2D:
  mov  bl, [ecx] //取下一个字符
  inc  ecx
  test bl, bl  //若为终止符,结束循环
  je  end_Dstr2D
  mul  edi   //乘10
  sub  bl, 48  //将数字字符转化为对应数字值
  movzx ebx, bl
  add  eax, ebx
  jmp  L_Dstr2D
end_Dstr2D:
  //平衡堆栈
  pop  edi
  pop  edx
  pop  ebx
  ret
  //子程序Hstr2D
  //功能:将十六进制字符串转化为数据
  //参数:ecx 字符串存储地址
  //返回值:eax转化后的数据
Hstr2D:
  push ebx
  push edx
  push edi
  xor  eax, eax //eax置零
  mov  edi, 16  //乘数为16
  //开始转化
L_Hstr2D:
  mov  bl, [ecx] //取下一个字符
  inc  ecx
  test bl, bl  //若为终止符,结束循环
  je  end_Hstr2D
  mul  edi   //乘16
  //将十六进制字符转化为对应数字值
  sub  bl, 48
  cmp  bl, 10
  jb  not_char
  sub  bl, 7
not_char:
  movzx ebx, bl
  add  eax, ebx
  jmp  L_Hstr2D
end_Hstr2D:
  //平衡堆栈
  pop  edi
  pop  edx
  pop  ebx
  ret
  //子程序tw_str2D
  //功能:将十二进制字符串转化为数据
  //参数:ecx 字符串存储地址
  //返回值:eax 转化后的数据
tw_str2D:
  push ebx
  push edx
  push edi
  xor  eax, eax //eax置零
  mov  edi, 12  //乘数为12
  //开始转化
L_tw_str2D:
  mov  bl, [ecx] //取下一个字符
  inc  ecx
  test bl, bl  //若为终止符,结束循环
  je  end_tw_str2D
  mul  edi   //乘12
  //将十六进制字符转化为对应数字值
  sub  bl, 48
  cmp  bl, 10
  jb  not_char_tw_str
  sub  bl, 7
not_char_tw_str:
  movzx ebx, bl
  add  eax, ebx
  jmp  L_tw_str2D
end_tw_str2D:
  //平衡堆栈
  pop  edi
  pop  edx
  pop  ebx
  ret
  //子程序D2tr_str
  //功能:将数据转化为十三进制字符串
  //参数:ecx 待处理数据 edx 字符串存储地址
D2tr_str:
  //初始化
  push edi  
  push edx  
  mov  edi, edx
  mov  edx, ecx
  mov  bl, 13  //除数为13
  mov  ecx, 0
  mov  eax, edx //将待处理数分配在ax中
  //计算转化后的字符串长度
L_count:
  div  bl
  inc  ecx
  mov  ah, 0
  cmp  al, 0 //判定是否处理完成
  jne  L_count
  mov  [edi+ecx], 0 //添加终止符
  //装入字符
  mov  eax, edx //将待处理数分配在ax中
L_store:
  div  bl
  cmp  ah, 10 //判断对应十三进制是数字还是字母
  jl  Number_D2tr_str
  add  ah, 7 //如果对应十三进制是字母,则多加7
Number_D2tr_str:
  add  ah, 48
  dec  ecx
  mov  [edi+ecx], ah
  mov  ah, 0
  cmp  al, 0 //判定是否处理完成
  jne  L_store
  //平衡堆栈
  pop  edx
  pop  edi
  ret

1.无符号数转化为十六进制字符串

 unsigned int u;
 char s_44[9];
 printf("u = ");
 scanf("%u", &u);
 printf("u的十六进制表示为:%#X\n", u);
 _asm{
	  //初始化
	  mov  ecx, u
	  lea  edx, s_44
	  call D2Hstr
 }
 printf("转化为字符串输出为:%s\n", s_44);

2.输入一个字符,字符串格式输出其ascll码的十进制、十六进制和二进制。

 char c_45;
 char sd[4], sh[3], sb[9];
 printf("char = ");
 scanf("%c", &c_45);
 _asm{
	  movzx ecx, c_45
	  lea  edx, sd
	  call D2Dstr
	  movzx ecx, c_45
	  lea  edx, sh
	  call D2Hstr
	  movzx ecx, c_45
	  lea  edx, sb
	  call D2Bstr
 }
 printf("ascll码十进制值:%s\n", sd);
 printf("ascll码十六进制值:%s\n", sh);
 printf("ascll码二进制值:%s\n", sb);

3.统计字符串元音字母个数,按八进制字符串输出

 char s_46[81], s_out[12];
 printf("s = ");
 scanf("%s", s_46);
 _asm{
	  //统计元音字母个数
	  xor  ebx, ebx //计数器置零
	  lea  esi, s_46 //取字符串存储地址
	L_judge:
	  lodsb   //读取一个字符
	  movzx ecx, al
	  jcxz END
	  call judge_vowel //判定是否为元音字母
	  add  ebx, eax //修改计数器值
	  jmp  L_judge
	END:
	  //将结果转化为八进制字符串
	  mov  ecx, ebx
	  lea  edx, s_out
 	  call D2Ostr
 }
 printf("元音字母个数为(八进制):%s\n", s_out);

4.将十进制字符串转为十进制数据,然后转化为十六进制字符串

 char s_dec[33], s_hex[9];
 unsigned int n_47;
 printf("s_dec = ");
 scanf("%s", s_dec);
 _asm{
	  //转十进制数
	  lea  ecx, s_dec
	  call Dstr2D
	  mov  n_47, eax
	  //转十六进制字符串
	  mov  ecx, eax
	  lea  edx, s_hex
	  call D2Hstr
 }
 printf("对应十进制数为:%u\n", n_47);
 printf("对应十六进制字符串为:%s\n", s_hex);

5.将十六进制字符串转化为十进制数据

 char hex_str[10];
 printf("s_hex = ");
 scanf("%s", hex_str);
 unsigned int n;
 _asm{
	  lea  ecx, hex_str
	  call Hstr2D
	  mov  n, eax
 }
 printf("转化为十进制数为:%u\n", n);

6.将十二进制字符串转化为十三进制字符串

 char s_input[81], s_output[81];
 printf("十二进制:");
 scanf("%s", s_input);
 _asm{
	  lea  ecx, s_input
	  call tw_str2D
	  mov  ecx, eax
	  lea  edx, s_output
	  call D2tr_str
 }
 printf("十三进制:%s\n", s_output);

7.字符串格式输入两个自然数,字符串格式输出其和、差、积

 char s_a[20], s_b[20];
 char s_sum[20], s_diff[20], s_pro[20];
 printf("a = ");
 scanf("%s", s_a);
 printf("b = ");
 scanf("%s", s_b);
 _asm{
	  //将a转化为数值
	  lea  ecx, s_a
	  call Dstr2D
	  mov  edi, eax
	  //将b转化为数值
	  lea  ecx, s_b
	  call Dstr2D
	  mov  esi, eax
	  //求和
	  add  eax, edi
	  mov  ecx, eax
	  lea  edx, s_sum
	  call D2Dstr
	  //求差
	  mov  eax, edi
	  sub  eax, esi
	  test eax, eax
	  jge  L_3_7
	  neg  eax
	L_3_7:
	  mov  ecx, eax
	  lea  edx, s_diff
	  call D2Dstr
	  //求乘积
	  mov  eax, edi
	  mul  esi
	  mov  ecx, eax
	  lea  edx, s_pro
	  call D2Dstr
 }
 printf("和为:%s\n", s_sum);
 printf("差为:%s\n", s_diff);
 printf("积为:%s\n", s_pro);

8.字符串格式输入两个自然数,字符串格式输出其商和余数

 char s_c[20], s_d[20];
 char s_quotient[20], s_remainder[20];
 printf("c = ");
 scanf("%s", s_c);
 printf("d = ");
 scanf("%s", s_d);
 _asm{
	  //将a转化为数值
	  lea  ecx, s_c
	  call Dstr2D
	  mov  edi, eax
	  //将b转化为数值
	  lea  ecx, s_d
	  call Dstr2D
	  mov  esi, eax
	  //求商和余数
	  mov  edx, edi
	  and  edx, 0xffff0000
	  shr  edx, 16   //将高16位分配到ax
	  movzx eax, di   //将低16位分配到ax
	  div  si
	  movzx ecx, dx
	  lea  edx, s_remainder
	  push eax  //保护eax
	  call D2Dstr
	  pop  eax  //恢复eax
	  movzx ecx, ax
	  lea  edx, s_quotient
	  call D2Dstr
 }
 printf("商数为:%s\n", s_quotient);
 printf("余数为:%s\n", s_remainder);

9.将字符串中所有十进制数字字串转化为数据,求所有数的和

 char string[81];
 unsigned int n_52;
 printf("str = ");
 scanf("%s", string);
 _asm{
	  lea  esi, string //获取字符串存储地址
	  mov  ecx, 10  //乘数为10
	  xor  edi, edi //置零
	L_outside:
	  mov  bl, [esi] //取下一个字符
	  inc  esi
	  test bl, bl  //若为终止符,结束外层循环
	  je  end_outside
	  sub  bl, 48  //将数字字符转化为对应数字值
	  jl  L_outside //若不为数字字符,转至下个字符
	  cmp  bl, 9
	  jg  L_outside //若不为数字字符,转至下个字符
	  movzx eax, bl
	L_inside:
	  mov  bl, [esi] //取下一个字符
	  inc  esi
	  test bl, bl
	  je  end_inside //若为终止符,结束内层循环
	  sub  bl, 48  //将数字字符转化为对应数字值
	  jl  end_inside //若不为数字字符,结束内层循环
	  cmp  bl, 9
	  jg  end_inside //若不为数字字符,结束内层循环
	  movzx ebx, bl
	  mul  ecx   //乘10
	  add  eax, ebx
	  jmp  L_inside
	end_inside:
	  add  edi, eax //加上子串对应数据值
	  jmp  L_outside
	end_outside:
	  mov  n_52, edi
 }
 printf("数据之和为:%u", n_52);
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值