作业-1:汇编语言
黄芃洋 2021212021
题目要求
问题-1:
* 1.1 请结合程序上下文逻辑,分析当所实现的“排序算法”不能正确排序时,_check_flag 为零还是非零?
* 1.2 请分析 main函数的执行流程,画出其伪代码流程图;
问题-2:请理解给定的do_swap汇编函数功能,写出等价的 C 语言函数代码;提示需注意数据类型,如长度、有无符号等(unsigned char ?无符号 1 Byte 长的变量?)。
问题-3:请用汇编语言实现冒泡排序函数(需要有详尽的代码注释+运行结果截图);提示会调用到已给定的do_swap汇编函数
(提示会自动对所实现的冒泡排序函数进行重复测试,无需自行输入字符串;请注意回答上方的问题 1.2)
以下是作答:
问题-1
1.1
当所实现的“排序算法”不能正确排序时,_check_flag 为零。我们可以用不同方法进行判断,分析如下:
首先我们定位到_check_flag 的位置
第一句汇编指令将 _ check_flag 一字节数据值存入eax寄存器并进行无符号扩展;第二、三句汇编指令用于检查al寄存器中的值、也就是_check_flag是否为0,如果不为0,那么ZF将被清除、jne指令也就将跳转到标记为continue_test的位置
如果为0,那么就不跳转,继续执行接下来的指令,那么我们来看一下接下来的指令:
根据上下文关系以及初始化数据段(.data)中的内容,我们可以知道上面的这段指令代表排序错误,并会输出“Sorry but try it again!”等字样,因此可以判断此时实现的“排序算法”不能正确排序,_check_flag 为零。
当然我们也可以在标记为end_test_loop的位置判断出来,本段指令如下
第一句汇编指令将 _ check_flag 一字节数据值存入eax寄存器并进行无符号扩展;第二、三句汇编指令用于检查al寄存器中的值、也就是_ check_flag是否为0,如果为0,那么ZF将被设置、je指令也就将跳转到标记为end_main的位置,而如果跳转到标志为end_main处,则程序立刻停止,因此显然,为_check_flag为0时“排序算法”不是正确排序
同时我们来接着往下看如果_ check_flag非零的情况,根据上下文关系以及初始化数据段(.data)中的内容,我们可以知道上面的这段指令代表排序正确,并会输出“Well done!”等字样,因此可以判断此时实现的“排序算法”能正确排序。
当然,我们也可以直接看到在#Function-3# 对排序结果得正确性进行检查的函数中:
分析可知,当发现排序错误时,它会将 _ check_flag置零
综上反复论证,我们可以得出结论:当所实现的“排序算法”不能正确排序时,_check_flag 为零
1.2
根据main函数的汇编指令可以得到其流程图如下:

问题-2
为了写出等价的c语言代码,首先我们来逐条分析并注释一下给定的do_swap汇编函数:
do_swap:
push ebp
mov ebp, esp
sub esp, 4
mov eax, DWORD PTR [ebp+8] #把位于内存地址ebp+8的4字节大小的值移入eax寄存器
movzx eax, BYTE PTR [eax] #访问eax中存储的地址并将该地址中的一字节数据放入eax中并进行无符号位扩展, 此时eax中存储的是变量1的值
mov BYTE PTR [ebp-1], al #将变量1的值填入ebp-1的位置
mov eax, DWORD PTR [ebp+12] #把位于内存地址ebp+12的四字节大小的值移入eax寄存器
movzx edx, BYTE PTR [eax] #访问eax中存储的地址并将该地址中的一字节数据放入edx中并进行无符号位扩展, 此时edx中存储的是变量2的值
mov eax, DWORD PTR [ebp+8] #把位于内存地址ebp+8的四字节大小的值移入eax寄存器
mov BYTE PTR [eax], dl #访问eax中存储的地址并将该地址中的一字节数据替换成dl中的值,也就相当于将变 量2的值存入变量1的位置
mov eax, DWORD PTR [ebp+12] #把位于内存地址ebp+12的四字节大小的值移入eax寄存器
movzx edx, BYTE PTR [ebp-1] #把位于ebp-1位置的一字节输入放入edx中进行无符号扩展,此时edx中存储的是变 量1的值
mov BYTE PTR [eax], dl #访问eax中存储的地址,并将该地址中一字节数据替换成dl中的值,也就相当于将变 量1的值存入变量2的位置
leave
ret
根据上面的分析,我们能够写出对应的C语言代码:
void do_swap(unsigned char *a, unsigned char *b) {
unsigned char temp = *a;
*a = *b;
*b = temp;
}
问题-3
为解决该问题,我们首先可以用C语言实现此功能,用以确定逻辑结构,下面是我先写出的C语言代码(并且还附上了do_swap函数的c代码实现,并配套了main函数用以调用和试验此函数):
//bubble sort
#include<stdio.h>
void bubble( unsigned char *arr);
void do_swap(unsigned char *a, unsigned char *b);
int main(){
unsigned char arr[]={'p','T','v','K','c','g','W','D','F','h'};
int i;
bubble(arr);
for(i=0;i<10;i++){
printf("%c",arr[i]);
}
}
void bubble( unsigned char *arr){
int j,k;
for(j=0;j<9;j++){
for(k=0;k<9-j;k++){
if(arr[k]<96){ //如果k大写
if(arr[k]>arr[k+1])do_swap(&arr[k],&arr[k+1]);//k+1也是大写且比k小
else if(arr[k+1]>96)do_swap(&arr[k],&arr[k+1]);//k+1是小写
else continue; //k+1是大写但是不比k小
}
else{//k是小写
if(arr[k+1]>96){//k+1也是小写
if(arr[k]>arr[k+1])do_swap(&arr[k],&arr[k+1]);
else continue;
}
else continue;
}
}
}
}
void do_swap(unsigned char *a, unsigned char *b) {
unsigned char temp = *a;
*a = *b;
*b = temp;
}
在确定了逻辑结构之后,使用汇编指令进行实现(我几乎为每一句指令都附上了注释):
#Function-4# 冒泡排序函数
do_bubble_sort: #*# 问题-3:请用汇编语言实现冒泡排序函数;
# 提示会调用到已给定的do_swap汇编函数
push ebp
mov ebp, esp
sub esp, 16
### ------------------------------------冒泡排序正文----------------------------------------开始
mov BYTE PTR[ebp-1], 0
jmp outerloop
initialize:
mov BYTE PTR[ebp-2], 0 #对k进行初始化
jmp innerloop #进入内循环
#-------------------------------------------------------------------
judgment:
movzx edx, BYTE PTR[ebp-2] #将k值移入edx中
movzx eax, byte ptr _char_list[edx] #将arr[k]的值存入eax
add edx,1 #k+1
movzx ebx, byte ptr _char_list[edx] #将arr[k+1]的值存入ebx
cmp al, 96 #将arr[k]和小写比较
ja k_lower #如果arr[k]是小写,则跳转到k_lower
k_capital:
cmp al,bl #比较arr[k]和arr[k+1]
ja swap #如果k>k+1 跳转swap
cmp bl,96 #将arr[k+1]和小写比较
ja swap #k+1是小写 跳转swap
jmp no_swap #其余跳转到 no_swap
k_lower:
cmp bl,96 #判断arr[k+1]是否为小写
jle no_swap #如果bl是大写则跳转到no_swap
cmp al,bl #是小写的话就来判断arr[k]和arr[k+1]的大小
ja swap #k+1<k 跳转swap
jmp no_swap #其余跳转到 no_swap
#-------------------------------------------------------------------
swap:
lea eax,byte ptr _char_list[edx] #将存储k+1的地址放入eax中
push eax
sub edx,1 #k
lea eax,byte ptr _char_list[edx] #将存储k的地址放入eax中
push eax
call do_swap
jmp kadd
no_swap:
jmp kadd
kadd:
movzx edx, BYTE PTR[ebp-2] #将k值移入edx中
add edx,1 #k值+1
mov BYTE PTR[ebp-2],dl #将新k值重新存入ebp-2位置
jmp innerloop #跳转到内循环的入口
#-------------------------------------------------------------------
innerloop:
mov eax, 9
movzx edx, BYTE PTR[ebp-2] #将k值移入edx中
movzx ebx, BYTE PTR[ebp-1] #将j值移入edx中
sub eax, ebx #9-j的值存入eax中
cmp eax, edx #对比9-j和k
ja judgment #9-j>k就跳转
#否则就进行j++
movzx ecx, BYTE PTR[ebp-1] #将j值移入ecx中
add ecx,1 #j值+1
mov BYTE PTR[ebp-1],cl #将新j值重新存入ebp-1位置
#并回到外循环
outerloop:
movzx ecx, BYTE PTR[ebp-1] #将j值移入ecx中
cmp ecx, 8 #判断j值与8的关系
jle initialize #若j小于等于8就进入内循环准备初始化
### ------------------------------------冒泡排序正文----------------------------------------结束
end_bubble_sort:
leave
ret
放入给到的程序中能得到如下的运行结果:

可知功能已经实现,汇编指令无误