1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
| .arch i386 .intel_syntax noprefix
.data .globl _char_list .globl _char_list_len .globl _check_flag .globl _test_no
.data _char_list_len: .byte 10 .bss .align 4 _char_list: .space 11
.data _check_flag: .byte 1 _test_no: .byte 1 .section .rdata,"dr" .align 4
.data hint_test_no: .ascii "\12-----------------------------test-%d\12\0" hint_given_array: .ascii "The given array: %s\12\0" hint_sorted_array: .ascii "The sorted array: %s\12\0"
hint_test_error_bar: .ascii "\12--!--!--!--!--!--!--!--!--!--test-%d\12\12\0" hint_test_error: .ascii "Sorry but try it again!\12\0" .align 4 hint_test_success_bar: .ascii "\12--*--*--*--*--*--*--*--*--*--passed!\12\12\0" hint_test_success: .ascii "Well done!\12\0"
.text .extern _printf .extern _puts .extern _time # C标准库函数:获取系统时间;可以用于设定随机数种子 .extern _srand # C标准库函数:用于设定随机数种子 .extern _rand # C标准库函数:生成随机数
.globl gen_random_list .globl do_swap .globl do_bubble_sort .globl check_sort .globl _main
#Function-1# 根据时间种子,随机生成由大小写英文字母构成的字符数组 gen_random_list: push ebp mov ebp, esp sub esp, 12
mov BYTE PTR [ebp-1], 0 in_gen_random_list_loop: movzx eax, BYTE PTR _char_list_len cmp BYTE PTR [ebp-1], al jnb end_gen_random_list
mov DWORD PTR [esp], 0 call _time mov edx, eax movzx eax, BYTE PTR [ebp-1] add edx, eax movzx eax, BYTE PTR _test_no movzx eax, al add eax, edx mov DWORD PTR [esp], eax call _srand
call _rand and eax, 1 test eax, eax setne al test al, al je in_gen_lower_letter
call _rand mov ecx, eax mov edx, 0x4EC4EC4F mov eax, ecx imul edx sar edx, 3 mov eax, ecx sar eax, 31 # 算数右移指令;其中,与逻辑右移shr 补 0 不同,sar 补位时,最高位保持不变 sub edx, eax mov eax, edx imul eax, eax, 26 # 有符号乘法指令,eax * 26 --所得乘积放入--> eax sub ecx, eax mov eax, ecx mov edx, eax movzx eax, BYTE PTR [ebp-1] add edx, 65 mov BYTE PTR _char_list[eax], dl
jmp in_gen_upper_letter
in_gen_lower_letter: call _rand mov ecx, eax mov edx, 0x4EC4EC4F mov eax, ecx imul edx sar edx, 3 # 算数右移指令;其中,与逻辑右移shr 补 0 不同,sar 补位时,最高位保持不变 mov eax, ecx sar eax, 31 sub edx, eax mov eax, edx imul eax, eax, 26 sub ecx, eax mov eax, ecx mov edx, eax movzx eax, BYTE PTR [ebp-1] add edx, 97 mov BYTE PTR _char_list[eax], dl
in_gen_upper_letter: movzx eax, BYTE PTR [ebp-1] add eax, 1 mov BYTE PTR [ebp-1], al jmp in_gen_random_list_loop
end_gen_random_list: movzx eax, BYTE PTR _char_list_len movzx eax, al mov BYTE PTR _char_list[eax], 0 # 字符数组末尾置零,方便按字符串进行一次性整体打印
movzx eax, BYTE PTR _test_no movzx eax, al
mov DWORD PTR [esp+4], eax mov DWORD PTR [esp], OFFSET FLAT:hint_test_no call _printf
mov DWORD PTR [esp+4], OFFSET FLAT:_char_list mov DWORD PTR [esp], OFFSET FLAT:hint_given_array call _printf
leave ret
#Function-2# 实现交换两个指针各自指向的数据内容 do_swap: #*# 问题-2:请理解已给定的do_swap汇编函数功能,写出等价的 C 语言函数代码 # 提示需注意数据类型,如长度、有无符号等 push ebp mov ebp, esp sub esp, 4
mov eax, DWORD PTR [ebp+8] movzx eax, BYTE PTR [eax] mov BYTE PTR [ebp-1], al
mov eax, DWORD PTR [ebp+12] movzx edx, BYTE PTR [eax] mov eax, DWORD PTR [ebp+8] mov BYTE PTR [eax], dl
mov eax, DWORD PTR [ebp+12] movzx edx, BYTE PTR [ebp-1] mov BYTE PTR [eax], dl
leave ret
#Function-3# 对排序结果得正确性进行检查 check_sort: push ebp mov ebp, esp sub esp, 12
mov DWORD PTR [esp+4], OFFSET FLAT:_char_list mov DWORD PTR [esp], OFFSET FLAT:hint_sorted_array call _printf
mov BYTE PTR [ebp-1], 0
in_check_loop: movzx eax, BYTE PTR [ebp-1] movzx edx, BYTE PTR _char_list_len movzx edx, dl sub edx, 1 cmp eax, edx jge end_check_sort
movzx eax, BYTE PTR [ebp-1] movzx edx, BYTE PTR _char_list[eax] movzx eax, BYTE PTR [ebp-1] add eax, 1 movzx eax, BYTE PTR _char_list[eax] cmp dl, al jbe in_error_check
movzx eax, BYTE PTR [ebp-1] movzx eax, BYTE PTR _char_list[eax] cmp al, 96 jbe in_error_marked
movzx eax, BYTE PTR [ebp-1] add eax, 1 movzx eax, BYTE PTR _char_list[eax] cmp al, 90 jbe continue_in_check_loop
in_error_marked: mov BYTE PTR _check_flag, 0 jmp end_check_sort
in_error_check: movzx eax, BYTE PTR [ebp-1] movzx eax, BYTE PTR _char_list[eax] cmp al, 90 ja continue_in_check_loop
movzx eax, BYTE PTR [ebp-1] add eax, 1 movzx eax, BYTE PTR _char_list[eax] cmp al, 96 jbe continue_in_check_loop
mov BYTE PTR _check_flag, 0 jmp end_check_sort
continue_in_check_loop: movzx eax, BYTE PTR [ebp-1] add eax, 1 mov BYTE PTR [ebp-1], al jmp in_check_loop
end_check_sort: leave ret
#Function-4# 冒泡排序函数 do_bubble_sort: push ebp mov ebp, esp sub esp, 16
### ------------------------------冒泡排序正文----------------------------开始 #选择从后往前冒泡 #使用局部变量区存储计数器,可以避免在调用do_swap的过程中计数器的值被子函数修改 mov BYTE PTR [ebp-8], 0 #外层循环计数器,将其存在局部变量区 movzx ebx, BYTE PTR _char_list_len #数组长度存入ebx寄存器 outer_loop: mov BYTE PTR [ebp-9], 0 #标志位,记录是否发生了交换 mov cl, BYTE PTR [ebp-8]#将外层循环计数器的值调入寄存器中,准备进行比较 movzx ecx, cl cmp ecx, ebx #比较最后一个元素下标和循环计数器的值 jae end_bubble_sort #如果循环次数已经和数组下标-1相等(即已经排序到最后一个元素)则排序结束
mov BYTE PTR [ebp-4], bl #内层循环计数器 dec BYTE PTR [ebp-4] #内层循环计数器,初始值是数组长度-1,表示数组最后一个元素的下标,并且每一轮都-1 inner_loop: #内层循环,进行一次的冒泡(交换) movzx esi, BYTE PTR [ebp-4]#将两个计数器装入通用寄存器 movzx edi, BYTE PTR [ebp-8] cmp esi, edi #比较循环计数器与最后一个元素的下标值 jbe end_inner_loop #如果相等则表示一轮冒泡结束,跳转到退出内层循环 mov eax, esi #将内层循环计数器的值放入通用寄存器 mov edx, eax #将右指针存入edx,即将后面的字符存入edx,此时edx的值是数组的最后一个未排序元素的下标 dec eax #此时eax存的是前一个字符的下标 mov edi, eax #edi此时的索引值就是左指针(前一个字符)
movzx eax, BYTE PTR _char_list[edi] #将前一个字符装入eax movzx edx, BYTE PTR _char_list[esi] #将后一个字符装入edx #一个更优的写法,先将字符存入局部变量区,需要时再移入寄存器,这样可以防止因寄存器被修改导致字符丢失,不过此处由于是连续使用字符所以也无需这样做 #mov DWORD PTR [ebp-10], eax #存储左指针地址 #mov DWORD PTR [ebp-12], edx #存储右指针地址 #进行大小写检查,由于大写字母ASCII码从65开始,因此可以在比较的时候将小写字母-58将其接到大写字母前面使得其一定比大写字母小 cmp eax, 97 #小写字母ASCII起始值为97 jae transfer_a #如果是小写字母就让它-58 cmp edx, 97 #接着检查下一个字符是否为小写字符 jae transfer_b jmp compare
transfer_a: #要按顺序跳转才行 sub eax, 58 cmp edx, 97 #检查下一个字符是否为小写字符 jae transfer_b jmp compare transfer_b: sub edx, 58 #如果是小写字母就让它-58 compare: cmp edx, eax #比较前后两个元素的值(ASCII码) jae not_swap #如果前面的元素小于后面的元素值则不交换 lea eax, BYTE PTR _char_list[edi] # 计算左指针地址,存入eax寄存器,准备压入函数栈 push eax inc edi #edi+1索引到右指针 lea eax, BYTE PTR _char_list[edi] # 计算右指针地址,存入eax寄存器,准备压入函数栈 push eax call do_swap #调用do_swap,交换前后两个元素 add esp, 8 #往函数栈中压入了两个字符,esp栈寄存器+8,由于每次调用函数都会重新设置栈寄存器,所以在调用do_bubble_sort时会自动将esp还原 mov BYTE PTR [ebp-9], 1 #标志位设置为1,记录内层发生了交换
not_swap: dec BYTE PTR [ebp-4] #内层循环计数器-1 jmp inner_loop #回到内层循环,进行下一轮的比较
end_inner_loop: cmp BYTE PTR [ebp-9], 1 #测试标志位,检查是否发生了交换 jne end_bubble_sort #如果发生了交换就跳入外层循环,否则说明数组已经有序,直接结束排序 inc BYTE PTR [ebp-8] #外层循环计数器+1,表示已经进行完一轮冒泡 jmp outer_loop #进行下一轮冒泡
### ------------------------------冒泡排序正文----------------------------结束
end_bubble_sort: leave ret
#Function-5# 主函数 main _main: mov %ebp, %esp #for correct debugging push ebp mov ebp, esp sub esp, 8
test_loop: movzx eax, BYTE PTR _test_no cmp al, 100 # 对排序函数进行测试的总次数;提示:调试时可以将这里改小一点,如改为 2 ja end_test_loop # 通过判断两个无符号数之间的大小关系,如果 CF & ZF = 0,说明大于,则转移
call gen_random_list call do_bubble_sort call check_sort
movzx eax, BYTE PTR _check_flag test al, al jne continue_test
movzx eax, BYTE PTR _test_no movzx eax, al mov DWORD PTR [esp+4], eax mov DWORD PTR [esp], OFFSET FLAT:hint_test_error_bar call _printf mov DWORD PTR [esp], OFFSET FLAT:hint_test_error call _puts jmp end_test_loop
continue_test: movzx eax, BYTE PTR _test_no add eax, 1 mov BYTE PTR _test_no, al jmp test_loop
end_test_loop: movzx eax, BYTE PTR _check_flag test al, al je _end_main
mov DWORD PTR [esp], OFFSET FLAT:hint_test_success_bar call _printf
mov DWORD PTR [esp], OFFSET FLAT:hint_test_success call _puts
_end_main: mov eax, 0
leave ret
|