子程序参数调用约定:
寄存器传参:使用方便,但可分配参数少
堆栈传参:较为复杂,但可安排足够多的局部变量。需注意进出栈的平衡
子程序设计过程中应使子程序和主程序保持某种默契,采用某一种约定。
例:在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);