高级语言基础结构的汇编形式

if结构

  • C语言源码
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char** argv){
    int a, b, c;
    scanf("%d%d", &a, &b);
    if(a > b){
        c = a - b;
    }
    else {
        c = b - a;
    }
    printf("%d", c);
    return 0;
}

定位主函数,得到main函数的汇编代码

00401500    55              push ebp
00401501    89E5            mov ebp,esp
00401503    83E4 F0         and esp,-0x10                                ; 使栈地址 16 字节对齐
00401506    83EC 20         sub esp,0x20                                 ; 开辟0x20字节的栈空间
00401509    E8 C2090000     call IF_struc.00401ED0
0040150E    8D4424 14       lea eax,dword ptr ss:[esp+0x14]              ; 变量b的地址
00401512    894424 08       mov dword ptr ss:[esp+0x8],eax               ; 第三个参数
00401516    8D4424 18       lea eax,dword ptr ss:[esp+0x18]              ; 变量a的地址
0040151A    894424 04       mov dword ptr ss:[esp+0x4],eax               ; 第二个参数
0040151E    C70424 00404000 mov dword ptr ss:[esp],IF_struc.00404000     ; %d%d,第一个参数
00401525    E8 1E110000     call <jmp.&msvcrt.scanf>
0040152A    8B5424 18       mov edx,dword ptr ss:[esp+0x18]              ; 变量a的值
0040152E    8B4424 14       mov eax,dword ptr ss:[esp+0x14]              ; 变量b的值
00401532    39C2            cmp edx,eax
00401534    7E 12           jle short IF_struc.00401548                  ; edx<=eax,即a<=b则跳转
00401536    8B5424 18       mov edx,dword ptr ss:[esp+0x18]
0040153A    8B4424 14       mov eax,dword ptr ss:[esp+0x14]
0040153E    29C2            sub edx,eax
00401540    89D0            mov eax,edx
00401542    894424 1C       mov dword ptr ss:[esp+0x1C],eax
00401546    EB 10           jmp short IF_struc.00401558                  ; 跳过else
00401548    8B5424 14       mov edx,dword ptr ss:[esp+0x14]
0040154C    8B4424 18       mov eax,dword ptr ss:[esp+0x18]
00401550    29C2            sub edx,eax
00401552    89D0            mov eax,edx
00401554    894424 1C       mov dword ptr ss:[esp+0x1C],eax
00401558    8B4424 1C       mov eax,dword ptr ss:[esp+0x1C]
0040155C    894424 04       mov dword ptr ss:[esp+0x4],eax
00401560    C70424 05404000 mov dword ptr ss:[esp],IF_struc.00404005     ; %d
00401567    E8 E4100000     call <jmp.&msvcrt.printf>
0040156C    B8 00000000     mov eax,0x0
00401571    C9              leave
00401572    C3              retn

通过一个cmp、jle或者其他跳转语句和一个jmp来实现if结构;

jmp语句用来跳过else结构,直接执行if-else结构后的语句;

cmp用来比较是否满足if条件,满足则通过跳转语句跳过if,进而直接执行else结构;

for结构

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char** argv){
	int n, sum=0;
	scanf("%d", &n);
	for(int i=1; i<=n; i++){
		sum += i;
	}
	printf("%d", sum);
	return 0;
} 

定位到main函数

00401500    55              push ebp                                 ; 开辟一个新的栈空间
00401501    89E5            mov ebp,esp
00401503    83E4 F0         and esp,-0x10                            ; 使栈地址16字节对齐
00401506    83EC 20         sub esp,0x20                             ; 开辟0x20字节大小的栈空间
00401509    E8 B2090000     call FOR_stru.00401EC0
0040150E    C74424 1C 00000>mov dword ptr ss:[esp+0x1C],0x0          ; 变量sum的初始化赋值
00401516    8D4424 14       lea eax,dword ptr ss:[esp+0x14]          ; 变量n的地址
0040151A    894424 04       mov dword ptr ss:[esp+0x4],eax           ; 变量n,第二个参数
0040151E    C70424 00404000 mov dword ptr ss:[esp],FOR_stru.00404000 ; %d,第一个参数
00401525    E8 0E110000     call <jmp.&msvcrt.scanf>
0040152A    C74424 18 01000>mov dword ptr ss:[esp+0x18],0x1          ; 变量i初始化为1
00401532    EB 0D           jmp short FOR_stru.00401541              ; 跳转到for循环的结束判断
00401534    8B4424 18       mov eax,dword ptr ss:[esp+0x18]          ; 取出i的值放到eax
00401538    014424 1C       add dword ptr ss:[esp+0x1C],eax          ; sum = sum + i
0040153C    834424 18 01    add dword ptr ss:[esp+0x18],0x1          ; i++
00401541    8B4424 14       mov eax,dword ptr ss:[esp+0x14]          ; for循环结束判断
00401545    394424 18       cmp dword ptr ss:[esp+0x18],eax          ; 判断循环是否结束
00401549  ^ 7E E9           jle short FOR_stru.00401534              ; i<=n,则返回循环体内容继续执行
0040154B    8B4424 1C       mov eax,dword ptr ss:[esp+0x1C]          ; 取出sum值
0040154F    894424 04       mov dword ptr ss:[esp+0x4],eax
00401553    C70424 00404000 mov dword ptr ss:[esp],FOR_stru.00404000 ; %d
0040155A    E8 E1100000     call <jmp.&msvcrt.printf>                ; 输出sum值
0040155F    B8 00000000     mov eax,0x0
00401564    C9              leave
00401565    C3              retn

对于for结构,汇编代码首先的for中的序号进行初始化

随之直接跳转到结束判断结构,判断for循环是否结束;

若未结束,则跳转回到for循环内容进行执行;

然后在此来到循环体结束判断,判断循环体是否结束;结束则不执行跳转语句jle跳回循环结构内容中,直接跳出循环,执行后续内容;

进而循环反复执行for循环体的内容

for结构也是通过一个jmp语句、跳转语句和一个判断结构完成的;

while结构

#include<stdio.h>
#include<stdlib.h>

void judge(int standard, int* end, int num){
	if(standard == num){
		*end = 0;
		printf("恭喜你猜中了,数字以666的形式送给你!!");
	}
	else{
		printf("猜错了呢!!真可惜!!!\n");
	}
}

int main(int argc, char** argv){
	int a = 30;
	int end = 1;
	int guessnum;
	while(end){
		printf("请输入你猜测的数字: ");
		scanf("%d", &guessnum);
		judge(a, &end, guessnum);
	} 
	return 0;
}
00401533    55              push ebp
00401534    89E5            mov ebp,esp
00401536    83E4 F0         and esp,-0x10
00401539    83EC 20         sub esp,0x20
0040153C    E8 AF090000     call WHILE_st.00401EF0
00401541    C74424 1C 1E000>mov dword ptr ss:[esp+0x1C],0x1E                 ; 第一个变量初始化为30
00401549    C74424 18 01000>mov dword ptr ss:[esp+0x18],0x1                  ; 第二个变量初始化为1
00401551    EB 3C           jmp short WHILE_st.0040158F
00401553    C70424 41404000 mov dword ptr ss:[esp],WHILE_st.00404041         ; 请输入你猜测的数字:
0040155A    E8 09110000     call <jmp.&msvcrt.printf>                        ; 输出函数,这种输出地址值,一般为输出提示符
0040155F    8D4424 14       lea eax,dword ptr ss:[esp+0x14]                  ; 取出第三个变量的地址
00401563    894424 04       mov dword ptr ss:[esp+0x4],eax                   ; 作为scanf函数的第二个参数
00401567    C70424 56404000 mov dword ptr ss:[esp],WHILE_st.00404056         ; %d
0040156E    E8 05110000     call <jmp.&msvcrt.scanf>
00401573    8B4424 14       mov eax,dword ptr ss:[esp+0x14]                  ; 第三个变量值取出放到eax
00401577    894424 08       mov dword ptr ss:[esp+0x8],eax                   ; 第三个变量是第三个参数
0040157B    8D4424 18       lea eax,dword ptr ss:[esp+0x18]
0040157F    894424 04       mov dword ptr ss:[esp+0x4],eax                   ; 第二个变量是第二个参数
00401583    8B4424 1C       mov eax,dword ptr ss:[esp+0x1C]
00401587    890424          mov dword ptr ss:[esp],eax                       ; 第一个变量是第一个参数
0040158A    E8 71FFFFFF     call WHILE_st.00401500                           ; 这个函数需要三个参数
0040158F    8B4424 18       mov eax,dword ptr ss:[esp+0x18]
00401593    85C0            test eax,eax                                     ; 判断第二个变量是否为0
00401595  ^ 75 BC           jnz short WHILE_st.00401553                      ; 第二个变量作为结束循环的标准
00401597    B8 00000000     mov eax,0x0
0040159C    C9              leave
0040159D    C3              retn


while结构和for结构的区别就在于是否有初始化值的过程

当然while结构也同样可以转换成for结构,for结构也可以用while结构来表示

这两个结构都是用某一个变量作为循环结束评判的标准,但是在for结构中比较明显的就是在循环体的末尾,也就是在判断标准之前通常会有一个标准++的操作,也就是常见的i++操作

这里有点调皮了,还加了个函数调用的结构,也可以简单看看把,反正不太影响观察while结构;

do-while结构

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char** argv){
	int a;
	scanf("%d", &a);
	do{
		a--;
	}while(a>1);
	printf("%d", a);
	return 0;
}
00401500    55              push ebp
00401501    89E5            mov ebp,esp
00401503    83E4 F0         and esp,-0x10
00401506    83EC 20         sub esp,0x20
00401509    E8 A2090000     call DO-WHILE.00401EB0
0040150E    8D4424 1C       lea eax,dword ptr ss:[esp+0x1C]
00401512    894424 04       mov dword ptr ss:[esp+0x4],eax
00401516    C70424 00404000 mov dword ptr ss:[esp],DO-WHILE.00404000 ; %d
0040151D    E8 06110000     call <jmp.&msvcrt.scanf>
00401522    8B4424 1C       mov eax,dword ptr ss:[esp+0x1C]
00401526    83E8 01         sub eax,0x1
00401529    894424 1C       mov dword ptr ss:[esp+0x1C],eax
0040152D    8B4424 1C       mov eax,dword ptr ss:[esp+0x1C]
00401531    83F8 01         cmp eax,0x1
00401534  ^ 7F EC           jg short DO-WHILE.00401522               ; a > b则跳转
00401536    8B4424 1C       mov eax,dword ptr ss:[esp+0x1C]          ; %d
0040153A    894424 04       mov dword ptr ss:[esp+0x4],eax
0040153E    C70424 00404000 mov dword ptr ss:[esp],DO-WHILE.00404000 ; ASCII "%d"
00401545    E8 E6100000     call <jmp.&msvcrt.printf>
0040154A    B8 00000000     mov eax,0x0
0040154F    C9              leave
00401550    C3              retn


这个结构其实和while与for结构的区别就是是否一开始就先进行一次循环结束判断;

在do-while结构中是先执行一次循环体的内容,在进行循环结束的判断,这就是do-while结构与while和for的不同之处

也就是到时候由汇编转成高级语言的辨认之处;

还有一个就是jg跳转的条件是a>b,但是有时候用test作为判断条件,当test成立时跳转,即test判断的寄存器为0时;

switch结构

#include<stdio.h>
#include<stdlib.h>

int main(int argv, char** argc){
	int sel;
	scanf("%d", &sel);
	switch(sel){
		case 1:
			printf("select the first one!");
			break;
		case 2:
			printf("select the second!");
			break;
		case 3:
			printf("select the third!");
			break;
		default:
			printf("error selection!");
			break;
	}
	return 0;
}
00401500    55              push ebp
00401501    89E5            mov ebp,esp
00401503    83E4 F0         and esp,-0x10
00401506    83EC 20         sub esp,0x20
00401509    E8 C2090000     call SWITCH_s.00401ED0
0040150E    8D4424 1C       lea eax,dword ptr ss:[esp+0x1C]
00401512    894424 04       mov dword ptr ss:[esp+0x4],eax
00401516    C70424 00404000 mov dword ptr ss:[esp],SWITCH_s.00404000 ; %d
0040151D    E8 26110000     call <jmp.&msvcrt.scanf>
00401522    8B4424 1C       mov eax,dword ptr ss:[esp+0x1C]
00401526    83F8 02         cmp eax,0x2
00401529    74 18           je short SWITCH_s.00401543
0040152B    83F8 03         cmp eax,0x3
0040152E    74 21           je short SWITCH_s.00401551
00401530    83F8 01         cmp eax,0x1
00401533    75 2A           jnz short SWITCH_s.0040155F
00401535    C70424 03404000 mov dword ptr ss:[esp],SWITCH_s.00404003 ; select the first one!
0040153C    E8 0F110000     call <jmp.&msvcrt.printf>
00401541    EB 29           jmp short SWITCH_s.0040156C
00401543    C70424 19404000 mov dword ptr ss:[esp],SWITCH_s.00404019 ; select the second!
0040154A    E8 01110000     call <jmp.&msvcrt.printf>
0040154F    EB 1B           jmp short SWITCH_s.0040156C
00401551    C70424 2C404000 mov dword ptr ss:[esp],SWITCH_s.0040402C ; select the third!
00401558    E8 F3100000     call <jmp.&msvcrt.printf>
0040155D    EB 0D           jmp short SWITCH_s.0040156C
0040155F    C70424 3E404000 mov dword ptr ss:[esp],SWITCH_s.0040403E ; error selection!
00401566    E8 E5100000     call <jmp.&msvcrt.printf>
0040156B    90              nop
0040156C    B8 00000000     mov eax,0x0
00401571    C9              leave
00401572    C3              retn

通过观察汇编代码可以知道,switch结构和其他结构的不同之处在于存在非常多的cmp和jmp以及条件跳转语句,这也是辨认出是switch结构的标志

当然了,这些switch结构也可以用if结构来表示,但是由于跳转指令jmp的存在,switch结构就变得相当明显了。

所以用高级语言重写的时候,直接根据cmp的比较进行选择即可;

struct结构

#include <stdio.h>
#include <string.h> 
#include <stdlib.h>
 
struct student
{
    long num;
    char name[20];
    char sex;
    float score;
}; 

int main()
{
    struct student stu_1;
    struct student *p;  //定义一个相同类型的指针&#xff0c;*同类型*   
	p=&stu_1;
    stu_1.num=89101;
    strcpy(stu_1.name, "Li Lin&");
    stu_1.sex='M';
    stu_1.score=89.5;

    printf("NO. :%ld\nname: %s\nsex:%c\nscore:%f\n", stu_1.num, stu_1.name, stu_1.sex, stu_1.score);
    printf("NO. :%ld\nname: %s\nsex:%c\nscore:%f\n", (*p).num, (*p).name, (*p).sex, (*p).score);
	//对于指针其实可以换个方式
    //(*p).score 等价于 p-&gt;score
    return 0;
}
00401500    55              push ebp
00401501    89E5            mov ebp,esp
00401503    83E4 F0         and esp,-0x10                            ; 使栈地址 16 字节对齐
00401506    83EC 50         sub esp,0x50                             ; 开辟一个大小为0x50的栈空间
00401509    E8 020A0000     call STRUCT_s.00401F10
0040150E    8D4424 2C       lea eax,dword ptr ss:[esp+0x2C]          ; 取出一个地址
00401512    894424 4C       mov dword ptr ss:[esp+0x4C],eax          ; 将该地址放到最后一个变量f中
00401516    C74424 2C 0D5C0>mov dword ptr ss:[esp+0x2C],0x15C0D      ; 将该地址第五个变量的第一个值修改为0x15c0d(89101)
0040151E    8D4424 2C       lea eax,dword ptr ss:[esp+0x2C]
00401522    83C0 04         add eax,0x4
00401525    C700 4C69204C   mov dword ptr ds:[eax],0x4C20694C        ; 对[esp+0x30]开始定义字符串“Li Lin&”
0040152B    C740 04 696E260>mov dword ptr ds:[eax+0x4],0x266E69
00401532    C64424 44 4D    mov byte ptr ss:[esp+0x44],0x4D          ; char类型变量赋值为0x4D(M)
00401537    A1 24404000     mov eax,dword ptr ds:[0x404024]
0040153C    894424 48       mov dword ptr ss:[esp+0x48],eax
00401540    D94424 48       fld dword ptr ss:[esp+0x48]              ; 加载浮点数到堆栈中
00401544    0FB64424 44     movzx eax,byte ptr ss:[esp+0x44]
00401549    0FBED0          movsx edx,al
0040154C    8B4424 2C       mov eax,dword ptr ss:[esp+0x2C]
00401550    DD5C24 10       fstp qword ptr ss:[esp+0x10]             ; 放入浮点型参数
00401554    895424 0C       mov dword ptr ss:[esp+0xC],edx           ; 放入参数“M”
00401558    8D5424 2C       lea edx,dword ptr ss:[esp+0x2C]
0040155C    83C2 04         add edx,0x4
0040155F    895424 08       mov dword ptr ss:[esp+0x8],edx           ; 放入字符串地址
00401563    894424 04       mov dword ptr ss:[esp+0x4],eax           ; 放入序号参数
00401567    C70424 00404000 mov dword ptr ss:[esp],STRUCT_s.00404000 ; NO. :%ld\nname: %s\nsex:%c\nscore:%f\n
0040156E    E8 15110000     call <jmp.&msvcrt.printf>
00401573    8B4424 4C       mov eax,dword ptr ss:[esp+0x4C]
00401577    D940 1C         fld dword ptr ds:[eax+0x1C]
0040157A    8B4424 4C       mov eax,dword ptr ss:[esp+0x4C]
0040157E    0FB640 18       movzx eax,byte ptr ds:[eax+0x18]
00401582    0FBED0          movsx edx,al
00401585    8B4424 4C       mov eax,dword ptr ss:[esp+0x4C]
00401589    8D48 04         lea ecx,dword ptr ds:[eax+0x4]
0040158C    8B4424 4C       mov eax,dword ptr ss:[esp+0x4C]
00401590    8B00            mov eax,dword ptr ds:[eax]
00401592    DD5C24 10       fstp qword ptr ss:[esp+0x10]
00401596    895424 0C       mov dword ptr ss:[esp+0xC],edx
0040159A    894C24 08       mov dword ptr ss:[esp+0x8],ecx
0040159E    894424 04       mov dword ptr ss:[esp+0x4],eax
004015A2    C70424 00404000 mov dword ptr ss:[esp],STRUCT_s.00404000 ; NO. :%ld\nname: %s\nsex:%c\nscore:%f\n
004015A9    E8 DA100000     call <jmp.&msvcrt.printf>
004015AE    B8 00000000     mov eax,0x0
004015B3    C9              leave
004015B4    C3              retn


这里主要有新的汇编指令fld和fstp,对应了压栈和出栈指令,只不过这两个指令是针对于浮点数的压栈和出栈指令。

主要用于调用函数的时候需要压入浮点数的参数。

结构体的所有使用的空间都是在栈中开辟;

Array结构

#include<stdio.h>
int main()
{
	int array_1[2],array_2[2],array_3[2];
	array_1={3,4};
	array_2={8,9};
	//array_3={21,45};
	
	int i;

	for(i=0;i<2;i++)
	{
		array_3[i]=array_1[i]*array_2[i];
Printf(“array_3[%d]=%d\n”,i,array_3[i]);
	}
	
	return 0;
}

PUSH EBP                                 
MOV EBP,ESP
SUB ESP,5C
PUSH EBX
PUSH ESI
PUSH EDI
LEA EDI,DWORD PTR SS:[EBP-5C]	;栈顶位置地址
MOV ECX,17
MOV EAX,CCCCCCCC
REP STOS DWORD PTR ES:[EDI]		;对栈中空间复制中断指令
MOV DWORD PTR SS:[EBP-8],3   ; int array_1[2]={3,4};
MOV DWORD PTR SS:[EBP-4],4
MOV DWORD PTR SS:[EBP-10],8  ; int array_2[2]={8,9};
MOV DWORD PTR SS:[EBP-C],9
MOV DWORD PTR SS:[EBP-1C],0  ; for(i=0;i<2;i++),进行i的初始化复制
JMP SHORT array1.00401056
MOV EAX,DWORD PTR SS:[EBP-1C]	;第7个局部参数i
ADD EAX,1
MOV DWORD PTR SS:[EBP-1C],EAX
CMP DWORD PTR SS:[EBP-1C],2
JGE SHORT array1.0040108D
MOV ECX,DWORD PTR SS:[EBP-1C]           ; array1的索引
MOV EDX,DWORD PTR SS:[EBP-1C]			; array2的索引
MOV EAX,DWORD PTR SS:[EBP+ECX*4-8]    ;数组array_1,ecx不会大于2的
IMUL EAX,DWORD PTR SS:[EBP+EDX*4-10]  ;乘法指令,EAX = EAX * DWORD PTR SS:[EBP+EDX*4-10],edx也不会大于2
MOV ECX,DWORD PTR SS:[EBP-1C]			; array3[2],将两数组相乘的结果放到array3[i]中
MOV DWORD PTR SS:[EBP+ECX*4-18],EAX		
MOV EDX,DWORD PTR SS:[EBP-1C]           ; printf("array_3[%d]=%d\n",i,array_3[i]);
MOV EAX,DWORD PTR SS:[EBP+EDX*4-18]
PUSH EAX
MOV ECX,DWORD PTR SS:[EBP-1C]
PUSH ECX
PUSH OFFSET array1.??_C@_0P@BAJC@array_>
CALL array1.printf
ADD ESP,0C
JMP SHORT array1.0040104D               ; }
XOR EAX,EAX                              ; return 0;
POP EDI                                  ; }
POP ESI
POP EBX
ADD ESP,5C
CMP EBP,ESP
CALL array1.__chkesp

Array结构其实比较难分辨,本次的汇编代码是由win7操作系统编译,然后反编译形成的;

比较容易辨认数组结构的是[EBP+ECX*4-8],其中ECX是数组的索引,EBP+ECX*4-8这个值当然是不会覆盖到下一个变量的地址;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值