今日は、線形探索(番兵法)。簡単そうだから。
#include <stdio.h> #include <stdlib.h> int search(int list[], int length, int target) { // 番兵(sentinel) list[length] = target; int i = 0; for (; i < length + 1; i++) { if (list[i] == target) break; } if (i != length + 1) { return i; // 見つかった } else { return -1; // 見つからなかった } } int main(void) { // target を探索 int target = 30; // 探索対象のリスト int length = 8; int *list; list = calloc(length + 1, sizeof(int)); if (list == NULL) return -1; list[0] = 23; list[1] = 43; list[2] = 11; list[3] = 64; list[4] = 91; list[5] = 75; list[6] = 30; list[7] = 58; // 線形探索 int index = search(list, length, target); free(list); // 結果の表示 if (index < length) { printf("%d 番目に見つかりました。\r\n", index + 1); return 0; } else if (index == length) { printf("見つかりませんでした。\r\n"); return 0; } else { printf("エラーが発生しました [index = %d]\r\n", index); return -1; } }
今日は、main 関数も読む。デバッグ用のコードを、ごりごり読む。
_main: 00D717A0 push ebp ; EBP を退避 00D717A1 mov ebp,esp ; ESP を退避(EBP ← ESP) 00D717A3 sub esp,0F0h ; ESP ← ESP−0xF0 00D717A9 push ebx ; EBX を退避 00D717AA push esi ; ESI を退避 00D717AB push edi ; EDI を退避 00D717AC lea edi,[ebp+FFFFFF10h] ; EDI ← EDI+0xF0 00D717B2 mov ecx,3Ch ; ECX ← 0x3C 00D717B7 mov eax,0CCCCCCCCh ; EAX ← 0xCCCCCCCC 00D717BC rep stos dword ptr es:[edi] ; EDI 番地 ← EAX(EDI が 4 減る) ; これを、ECX(0x3C)回繰り返す 00D717BE mov dword ptr [ebp-8],1Eh ; EBP−0x08 番地(target) ← 30 00D717C5 mov dword ptr [ebp-14h],8 ; EBP−0x14 番地(length) ← 8 00D717CC mov esi,esp ; ESI ← ESP 00D717CE push 4 ; 第 2 引数 sizeof(int) 00D717D0 mov eax,dword ptr [ebp-14h] ; EAX ← length 00D717D3 add eax,1 ; EAX ← length+1 00D717D6 push eax ; 第 1 引数 length+1 00D717D7 call dword ptr ds:[00D7B16Ch] ; [__imp__calloc] 00D717DD add esp,8 ; ESP を 2 段下へ(引数 2 つ分) 00D717E0 cmp esi,esp ; ESP がずれていないことを確認 00D717E2 call 00D71122 ; __RTC_CheckEsp 00D717E7 mov dword ptr [ebp-20h],eax ; EBP−0x20 番地(list)← EAX 00D717EA cmp dword ptr [ebp-20h],0 ; list と 0 を比較 00D717EE jne 00D717F8 ; 以降の処理へ進む 00D717F0 or eax,0FFFFFFFFh ; EAX ← −1 00D717F3 jmp 00D71905 ; 終了へ進む 00D717F8 mov eax,4 ; EAX ← 4 00D717FD imul ecx,eax,0 ; ECX ← EAX × 0 00D71800 mov edx,dword ptr [ebp-20h] ; EDX ← EBP−0x20(list)番地の値 00D71803 mov dword ptr [edx+ecx],17h ; EDX+ECX 番地(list[0]) ← 23 00D7180A mov eax,4 ; EAX ← 4 00D7180F shl eax,0 ; EAX ← EAX × 1(0 ビット左にずらす) 00D71812 mov ecx,dword ptr [ebp-20h] ; ECX ← EBP−0x20(list)番地の値 00D71815 mov dword ptr [ecx+eax],2Bh ; ECX+EAX 番地(list[1]) ← 43 ........ ... ....................... ; 途中略 00D71875 mov eax,4 ; EAX ← 4 00D7187A imul ecx,eax,7 ; ECX ← EAX × 7 00D7187D mov edx,dword ptr [ebp-20h] ; EDX ← EBP−0x20(list)番地の値 00D71880 mov dword ptr [edx+ecx],3Ah ; EDX+ECX 番地(list[7]) ← 58 00D71887 mov eax,dword ptr [ebp-8] ; EAX ← target 00D7188A push eax ; 第 3 引数 00D7188B mov ecx,dword ptr [ebp-14h] ; ECX ← length 00D7188E push ecx ; 第 2 引数 00D7188F mov edx,dword ptr [ebp-20h] ; EDX ← list 00D71892 push edx ; 第 1 引数 00D71893 call 00D71041 ; _search 00D71898 add esp,0Ch ; ESP を 3 段(引数 3 つ分)下へ 00D7189B mov dword ptr [ebp-2Ch],eax ; index 番地 ← EAX 00D7189E mov esi,esp ; ESI ← ESP 00D718A0 mov eax,dword ptr [ebp-20h] ; EAX ← list 00D718A3 push eax ; 引数 00D718A4 call dword ptr ds:[00D7B168h] ; [__imp__free] 00D718AA add esp,4 ; ESP を 1 段下へ 00D718AD cmp esi,esp ; ESI と ESP を比較 00D718AF call 00D71122 ; __RTC_CheckEsp 00D718B4 mov eax,dword ptr [ebp-2Ch] ; EAX ← EBP−2C(index)番地の値 00D718B7 cmp eax,dword ptr [ebp-14h] ; EAX(index)と length を比較 00D718BA jge 00D718D6 ; Jump if Greater or Equal 00D718BC mov eax,dword ptr [ebp-2Ch] ; EAX ← EBP−2C(index)番地の値 00D718BF add eax,1 ; EAX ← EAX+1 00D718C2 push eax ; 引数 index+1 00D718C3 push 0D77C08h ; 引数 "%d 番目に見つかりました。\r\n" 00D718C8 call 00D7132F ; _printf 00D718CD add esp,8 ; ESP を 2 段下へ(引数 2 つ分) 00D718D0 xor eax,eax ; EAX ← 1(戻り値) 00D718D2 jmp 00D71905 ; 終了へ進む 00D718D4 jmp 00D71905 ; (なぜ jmp が 2 回ある?) 00D718D6 mov eax,dword ptr [ebp-2Ch] ; EAX ← EBP−2C(index)番地の値 00D718D9 cmp eax,dword ptr [ebp-14h] ; EAX(index)と length を比較 00D718DC jne 00D718F1 ; 00D718DE push 0D77B30h ; 引数 "見つかりませんでした。\r\n" 00D718E3 call 00D7132F ; _printf 00D718E8 add esp,4 ; ESP を 1 段下へ(引数 1 つ分) 00D718EB xor eax,eax ; EAX ← 1(戻り値) 00D718ED jmp 00D71905 ; 終了へ進む 00D718EF jmp 00D71905 ; (なぜ jmp が 2 回ある?) 00D718F1 mov eax,dword ptr [ebp-2Ch] ; EAX ← EBP−2C(index)番地の値 00D718F4 push eax ; 引数 index 00D718F5 push 0D77D08h ; 引数 "エラーが発生しました [index = %d]\r\n" 00D718FA call 00D7132F ; _printf 00D718FF add esp,8 ; ESP を 2 段下へ(引数 2 つ分) 00D71902 or eax,0FFFFFFFFh ; EAX ← −1(戻り値) 00D71905 pop edi ; EDI を戻す 00D71906 pop esi ; ESI を戻る 00D71907 pop ebx ; EBX を戻す 00D71908 add esp,0F0h ; ESP ← ESP+0xF0 00D7190E cmp ebp,esp ; EBP と ESP を比較する 00D71910 call 00D71122 ; __RTC_CheckEsp 00D71915 mov esp,ebp ; ESP ← EBP 00D71917 pop ebp ; EBP を戻す 00D71918 ret ; EAX の値(リターンコード)で終了
もちろん search 関数も読む。もりもり読む。
_search: ; 前処理 00D71A10 push ebp ; EBP を退避 00D71A11 mov ebp,esp ; ESP を退避(EBP ← ESP) 00D71A13 sub esp,0CCh ; ESP ← ESP−0xCC 00D71A19 push ebx ; EBX を退避 00D71A1A push esi ; ESI を退避 00D71A1B push edi ; EDI を退避 00D71A1C lea edi,[ebp+FFFFFF34h] ; EDI ← EBP+0xCC 00D71A22 mov ecx,33h ; ECX ← 0x33 00D71A27 mov eax,0CCCCCCCCh ; EAX ← 0xCCCCCCCC 00D71A2C rep stos dword ptr es:[edi] ; EDI 番地 ← EAX(EDI が 4 減る) ; これを、ECX(0x33)回繰り返す ; 初期値の設定 00D71A2E mov eax,dword ptr [ebp+0Ch] ; EAX ← EBP+0x0C(length)番地の値 00D71A31 mov ecx,dword ptr [ebp+8] ; ECX ← EBP+0x08(list)番地の値 00D71A34 mov edx,dword ptr [ebp+10h] ; EDX ← EBP+0x10(target)番地の値 00D71A37 mov dword ptr [ecx+eax*4],edx; ECX+EAX×4 番地 ← EDX 00D71A3A mov dword ptr [ebp-8],0 ; EBX−8(i)← 0 00D71A41 jmp 00D71A4C ; list と target のマッチングへ進む ; ループの処理(i のインクリメント) 00D71A43 mov eax,dword ptr [ebp-8] ; EAX ← i 00D71A46 add eax,1 ; i++ 00D71A49 mov dword ptr [ebp-8],eax ; EBP−8(i)番地 ← EAX(i++) ; ループの処理(list と target のマッチング) 00D71A4C mov eax,dword ptr [ebp+0Ch] ; EAX ← EBP+0x0C(length)番地の値 00D71A4F add eax,1 ; length+1 00D71A52 cmp dword ptr [ebp-8],eax ; EBP−8(i)の値と EAX を比較 00D71A55 jge 00D71A69 ; 見つかったかどうかの判定に進む 00D71A57 mov eax,dword ptr [ebp-8] ; EAX ← EBP−8(i)番地の値 00D71A5A mov ecx,dword ptr [ebp+8] ; ECX ← EBP+0x08(list)番地の値 00D71A5D mov edx,dword ptr [ecx+eax*4]; EDX ← list 番地から i 段下 00D71A60 cmp edx,dword ptr [ebp+10h] ; EDX と target を比較 00D71A63 jne 00D71A67 ; 2 行下へ進む 00D71A65 jmp 00D71A69 ; 見つかったかどうかの判定に進む 00D71A67 jmp 00D71A43 ; i のインクリメントへ進む ; ループの処理(見つかったかどうかの判定) 00D71A69 mov eax,dword ptr [ebp+0Ch] ; EAX ← EBP+0x0C(length)番地の値 00D71A6C add eax,1 ; length+1 00D71A6F cmp dword ptr [ebp-8],eax ; i の値と length+1 の値を比較 00D71A72 je 00D71A7B ; 4 行下へ進む 00D71A74 mov eax,dword ptr [ebp-8] ; EAX ← i 00D71A77 jmp 00D71A7E ; 後処理へ進む 00D71A79 jmp 00D71A7E ;(なぜ jmp が 2 回ある?) 00D71A7B or eax,0FFFFFFFFh ; EAX ← −1 ; 後処理 00D71A7E pop edi ; EDI を戻す 00D71A7F pop esi ; ESI を戻す 00D71A80 pop ebx ; EBX を戻す 00D71A81 mov esp,ebp ; ESP を戻す(ESB ← EBP) 00D71A83 pop ebp ; EBP を戻す 00D71A84 ret ; EAX の値(リターンコード)で終了
急いでいるので、コメント控えめで。