10.2 从C到X86电子课件 计算机系统基础:C语言视角(RISC-V版).ppt
10.2从C到X86电子课件计算机系统基础:C语言视角(RISC-V版)从从C C到到X86X86函数调用约定函数调用约定由于寄存器数量较少,局部变量和参数,都要由于寄存器数量较少,局部变量和参数,都要分配到栈帧中分配到栈帧中函数函数调用步骤调用步骤第一,调用函数第一,调用函数传递参数传递参数:将参数分配到栈帧的顶部,即低地址端;一般采用:将参数分配到栈帧的顶部,即低地址端;一般采用自右自右向左入栈向左入栈的方式的方式使用使用CALLCALL指令调用子例程指令调用子例程注意:注意:CALLCALL指令将指令将返回地址压栈返回地址压栈,此时,栈顶为返回地址,此时,栈顶为返回地址第二,被调用函数第二,被调用函数将帧指针寄存器将帧指针寄存器EBPEBP压栈压栈采用采用callee-savecallee-save策略策略将其他需要将其他需要保存的寄存器压栈保存的寄存器压栈调整帧指针调整帧指针,使其指向栈帧的高地址端,即指向保存,使其指向栈帧的高地址端,即指向保存EBPEBP寄存器的单寄存器的单元元分配栈帧分配栈帧注意:注意:X86X86要求要求栈帧对齐栈帧对齐,起始地址以,起始地址以4 4个个0 0结尾,结尾,栈帧的大小是栈帧的大小是1616的倍数的倍数将将局部变量分配到栈帧局部变量分配到栈帧中中第三,被调用函数第三,被调用函数执行任务执行任务使用使用帧指针帧指针访问栈帧中的局部变量,特别是读取调用者传来的参数,比使用栈访问栈帧中的局部变量,特别是读取调用者传来的参数,比使用栈指针访问更方便指针访问更方便如果函数有返回值,将如果函数有返回值,将返回值返回值存在存在EAXEAX寄存器中寄存器中第四,被调用函数第四,被调用函数执行结束,将保存的寄存器弹出,即执行结束,将保存的寄存器弹出,即恢复寄存器恢复寄存器使用使用LEAVELEAVE指令指令弹出栈帧弹出栈帧使用使用RETRET指令指令返回返回最后,最后,调用函数调用函数取回取回被调用函数的被调用函数的返回值返回值交换两个交换两个变量变量的的NewSwapNewSwap函数函数#include#include void NewSwap(int*firstVal,int*secondVal);void NewSwap(int*firstVal,int*secondVal);int main()int main()int valueA=3;int valueA=3;int valueB=4;int valueB=4;NewSwap NewSwap(&valueA,&valueB(&valueA,&valueB););printf(valueA=%d and valueB=%dn,valueA,valueB);printf(valueA=%d and valueB=%dn,valueA,valueB);void NewSwap(void NewSwap(int*firstValint*firstVal,int*secondValint*secondVal)int tempVal;int tempVal;tempVal=tempVal=*firstVal*firstVal;*firstVal *firstVal=*secondVal*secondVal;*secondVal *secondVal=tempVal;=tempVal;GCCGCC编译器编译器gcc gcc-S-S -masm=intel-masm=intel*.c*.c生成生成IntelIntel格式的格式的X86X86汇编汇编mainmain函数的汇编代码函数的汇编代码01.section.rdata,dr;只读数据区只读数据区02 LC0:03.ascii valueA=%d and valueB=%d12004.text;代码区代码区05.globl _main06;07 _main:08pushebp;保存保存EBP09movebp,esp;调整调整EBP0Aandesp,-16;栈帧对齐栈帧对齐0Bsubesp,32;分配栈帧分配栈帧0Ccall_main0DmovDWORD PTR esp+28,3 ;MESP+28-3,valueA=3;0EmovDWORD PTR esp+24,4 ;MESP+24-4,valueB=4;0Fleaeax,esp+24;EAX-ESP+24,&valueB10movDWORD PTR esp+4,eax;MESP+4-EAX,参数压栈参数压栈11leaeax,esp+28;EAX-ESP+28,&valueA12movDWORD PTR esp,eax;MESP-EAX,参数压栈参数压栈13call_NewSwap14movedx,DWORD PTR esp+24;EDX-MESP+24,valueB15moveax,DWORD PTR esp+28;EAX-MESP+28,valueA16movDWORD PTR esp+8,edx;MESP+8-EDX,参数压栈参数压栈17movDWORD PTR esp+4,eax;MESP+4-EAX,参数压栈参数压栈18movDWORD PTR esp,OFFSET FLAT:LC0;MESP-LC0,参数压栈参数压栈19call_printf1Amoveax,0;return 0;1Bleave;栈帧弹出栈帧弹出1Cret;返回返回调用调用printfprintf函数函数NewSwapNewSwap函数的汇编代码函数的汇编代码01.globl _NewSwap02;03 _NewSwap:04pushebp;保存保存EBP05movebp,esp;调整调整EBP06subesp,16;分配栈帧分配栈帧07moveax,DWORD PTR ebp+8;EAX-MEBP+8,firstVal,&valueA08moveax,DWORD PTR eax;EAX-MEAX,*firstVal09movDWORD PTR ebp-4,eax;MEBP-4-EAX,temp=*firstVal;0Amoveax,DWORD PTR ebp+12;EAX-MEBP+12,secondVal,&valueB0Bmovedx,DWORD PTR eax;EDX-MEAX,*secondVal0Cmoveax,DWORD PTR ebp+8;EAX-MEBP+8,firstVal,&valueA0DmovDWORD PTR eax,edx;MEAX-EDX,*firstVal=*secondVal;0Emoveax,DWORD PTR ebp+12;EAX-MEBP+12,secondVal,&valueB0Fmovedx,DWORD PTR ebp-4;EDX-MEBP-4,temp10movDWORD PTR eax,edx;MEAX-EDX,*secondVal=temp;11leave;栈帧弹出栈帧弹出12ret;返回返回BubbleSortBubbleSort函数函数1#include 1#include 2#define MAX_NUMS 102#define MAX_NUMS 103 34 void BubbleSort(int list4 void BubbleSort(int list,int);,int);5 56 int main()6 int main()7 7 8 8int index;int index;9 9int numbers MAX_NUMS;int numbers MAX_NUMS;10101111/*/*获取输入获取输入*/*/1212printf(Enter%d numbers.n,MAX_NUMS);printf(Enter%d numbers.n,MAX_NUMS);1313for(index=0;index MAX_NUMS;index+)for(index=0;index MAX_NUMS;index+)1414 1515printf(Input number%d:,index);printf(Input number%d:,index);1616scanf(%d,&numbersindex);scanf(%d,&numbersindex);1717 18181919/*/*调用排序程序调用排序程序*/*/2020BubbleSort(numbers,MAX_NUMS);BubbleSort(numbers,MAX_NUMS);21212222/*/*输出已排序的数组输出已排序的数组*/*/2323printf(nThe input set,in ascending order:n);printf(nThe input set,in ascending order:n);2424for(index=0;index MAX_NUMS;index+)for(index=0;index MAX_NUMS;index+)2525printf(%dn,numbersindex);printf(%dn,numbersindex);26 26 27272828void BubbleSort(int void BubbleSort(int listlist,int n),int n)2929 3030int i,j;int i,j;3131int temp;int temp;3232forfor(i=1;i=n-1;i+)(i=1;i=n-1;i+)3333for for(j=1;j=n-i;j+)(j=1;j listj)if(listj-1 listj)3535 3636temp=listj-1;temp=listj-1;3737listj-1 listj-1=listjlistj;38 38 listj=temp;listj=temp;3939 4040 mainmain函数的汇编代码函数的汇编代码01.text;代码区代码区02.globl_main03 ;04 _main:05pushebp;保存帧指针保存帧指针06movebp,esp;调整帧指针调整帧指针07andesp,-16;栈帧对齐栈帧对齐08subesp,64;分配栈帧分配栈帧09;0AmovDWORD PTR esp+60,0;Mesp+60-0,index=0;0B;省略调用省略调用scanf函数相关代码函数相关代码0CmovDWORD PTR esp+4,10;Mesp+4-10,参数,参数,n=100Dleaeax,esp+20;eax-esp+20,&numbers00EmovDWORD PTR esp,eax;Mesp-eax,参数参数,list=&numbers00Fcall_BubbleSort10;省略调用省略调用printf函数相关代码函数相关代码11moveax,0;return 0;12leave;栈帧弹出栈帧弹出13ret;返回返回BubbleSortBubbleSort0101.globl _BubbleSort.globl _BubbleSort02 _BubbleSort:02 _BubbleSort:0303pushpushebpebp;保存帧指针保存帧指针0404movmovebp,espebp,esp;调整帧指针调整帧指针0505subsubesp,16esp,16;分配栈帧分配栈帧0606movmovDWORD PTR ebp-4,1DWORD PTR ebp-4,1;Mebp-4-1,i=1;Mebp-4-1,i=1;0707jmpjmpL7L708 L11:08 L11:0909movmovDWORD PTR ebp-8,1DWORD PTR ebp-8,1;Mebp-8-1,j=1;Mebp-8-1,j=10A0AjmpjmpL8L80B L10:0B L10:0C0Cmovmoveax,DWORD PTR ebp-8eax,DWORD PTR ebp-8;j;j0D0Ddecdeceaxeax;j-1;j-10E0Esalsaleax,2eax,2;(j-1)*4;(j-1)*40F0Faddaddeax,DWORD PTR ebp+8eax,DWORD PTR ebp+8;eax-Mebp+8+(j-1)*4,&listj-1;eax-Mebp+8+(j-1)*4,&listj-11010movmovedx,DWORD PTR eaxedx,DWORD PTR eax;edx-Meax,listj-1;edxlistj)temp=listj-1;listj-1=listj;listj=temp;1111movmoveax,DWORD PTR ebp-8eax,DWORD PTR ebp-8;j;j1212salsaleax,2eax,2;j*4;j*41313addaddeax,DWORD PTR ebp+8eax,DWORD PTR ebp+8;eax-Mebp+8+(j)*4,&listj;eax-Mebp+8+(j)*4,&listj1414movmoveax,DWORD PTR eaxeax,DWORD PTR eax;listj;listj1515cmpcmpedx,eaxedx,eax;listj-1-listj;listj-1-listj1616jlejleL9L9;listj-1=listj?;listj-1=listj?1717movmoveax,DWORD PTR ebp-8eax,DWORD PTR ebp-8;j;j1818decdeceaxeax;j-1;j-11919salsaleax,2eax,2;(j-1)*4;(j-1)*41A1Aaddaddeax,DWORD PTR ebp+8eax,DWORD PTR ebp+8;&listj-1;&listj-11B1Bmovmoveax,DWORD PTR eaxeax,DWORD PTR eax;listj-1;listj-11C1CmovmovDWORD PTR ebp-12,eaxDWORD PTR ebp-12,eax;Mebp-12-eax,temp=listj-1;Mebp-12listj)temp=listj-1;listj-1=listj;listj=temp;1D1Dmovmoveax,DWORD PTR ebp-8eax,DWORD PTR ebp-8;j;j1E1Edecdeceaxeax;j-1;j-11F1Fsalsaleax,2eax,2;(j-1)*4;(j-1)*42020addaddeax,DWORD PTR ebp+8eax,DWORD PTR ebp+8;&listj-1;&listj-12121movmovedx,DWORD PTR ebp-8edx,DWORD PTR ebp-8;j;j2222salsaledx,2edx,2;j*4;j*42323addaddedx,DWORD PTR ebp+8edx,DWORD PTR ebp+8;&listj;&listj2424movmovedx,DWORD PTR edxedx,DWORD PTR edx;listj;listj2525movmovDWORD PTR eax,edxDWORD PTR eax,edx;listj-1=listj;listj-1=listj;2626movmoveax,DWORD PTR ebp-8eax,DWORD PTR ebp-8;j;j2727salsaleax,2eax,2;j*4;j*42828addaddeax,DWORD PTR ebp+8eax,DWORD PTR ebp+8;&listj;&listj2929movmovedx,DWORD PTR ebp-12edx,DWORD PTR ebp-12;temp;temp2A2AmovmovDWORD PTR eax,edxDWORD PTR eax,edx;listj=temp;listj=temp;if(listj-1listj)temp=listj-1;listj-1=listj;listj=temp;2B2BL9:L9:2C2CincincDWORD PTR ebp-8DWORD PTR ebp-8;j+;j+2D2DL8:L8:2E2Emovmoveax,DWORD PTR ebp-4eax,DWORD PTR ebp-4;i;i2F2Fmovmovedx,DWORD PTR ebp+12edx,DWORD PTR ebp+12;形参形参n n3030movmovecx,edxecx,edx3131subsubecx,eaxecx,eax;n-i;n-i3232movmoveax,ecxeax,ecx3333cmpcmpeax,DWORD PTR ebp-8eax,DWORD PTR ebp-8;n-i-j;n-i-j3434jgejgeL10L10;n-i=j;n-i=j3535incincDWORD PTR ebp-4DWORD PTR ebp-4;i+;i+3636L7:L7:3737movmoveax,DWORD PTR ebp+12eax,DWORD PTR ebp+12;n;n3838decdeceaxeax;n-1;n-13939cmpcmpeax,DWORD PTR ebp-4eax,DWORD PTR ebp-4;n-1-i;n-1-i3A3AjgejgeL11L11;n-1=i;n-1=i3B3Bleaveleave;栈帧弹出栈帧弹出3 3C Cretret;返回返回DECDEC指令指令算术运算指令,功能:递减算术运算指令,功能:递减SALSAL指令指令算术左移运算,即乘算术左移运算,即乘2 2的的n n次方次方由于由于X86X86的通用寄存器较少,且只有的通用寄存器较少,且只有EAXEAX和和EDXEDX可用于运算过程中存储临时数据,所以,重复可用于运算过程中存储临时数据,所以,重复代码较多代码较多例如,多次出现例如,多次出现计算计算&listj-1&listj-1计算计算&listj&listj编译器与编译器与+/-+/-运算符运算符将将+与其他运算符混合使用的表达式与其他运算符混合使用的表达式#includeintmain()intsum=0;inti=0;sum=sum+i;printf(%d%dn,sum,i);Visual StudioVisual Studio编译运行,打印结果为编译运行,打印结果为“1 0”1 0”sumsum的计算结果为的计算结果为1 1,i i不变不变在在Visual StudioVisual Studio集成开发环境中,通过在集成开发环境中,通过在“sum=sum+i;”sum=sum+i;”语句处设置断点,开始调语句处设置断点,开始调试,打开反汇编窗口和内存窗口,可以查看该试,打开反汇编窗口和内存窗口,可以查看该语句编译后的汇编代码语句编译后的汇编代码分析分析等价于:等价于:;sum=sum+i;01moveax,dword ptr sum;EAX-Msum,002addeax,dword ptr i;EAX-EAX+Mi,003movdword ptr sum,eax;Msum-EAX,004movecx,dword ptr sum;ECX-Msum,005addecx,1;ECX-ECX+106movdword ptr sum,ecx;Msum-ECX,1sum=sum+i;sum=sum+1;Dev-C+Dev-C+编译运行,打印结果为编译运行,打印结果为“0 0”0 0”sumsum的计算结果为的计算结果为0 0,i i不变不变Dev-C+Dev-C+使用的是使用的是GCCGCC编译器,使用该编译器的编译器,使用该编译器的编译命令编译命令gcc-S-masm=intel-m32*.cgcc-S-masm=intel-m32*.c生成生成IntelIntel格式的格式的X86X86汇编文件汇编文件分析分析等价于:等价于:01moveax,DWORD PTR esp+28;EAX-MESP+28,sum02leaedx,eax+1;EDX-EAX+1,sum+103movDWORD PTR esp+28,edx;MESP+28-EDX,sum=sum+104movedx,DWORD PTR esp+24;EDX-MESP+24,i05addeax,edx;EAX-EAX+EDX,sum递递加前的加前的值值+i,006movDWORD PTR esp+28,eax;MEBP-4-EAX,sum=0sum1=sum0+1;sum1=sum0+i;在一个混合了多种运算符的表达式中,对于自在一个混合了多种运算符的表达式中,对于自增或自减运算符的求值顺序,是取决于编译器增或自减运算符的求值顺序,是取决于编译器的的因为对于这种表达式中的因为对于这种表达式中的“+/-”+/-”求值顺序,求值顺序,是是C C标准中没有明确定义标准中没有明确定义的,编译器可以自行的,编译器可以自行定义,不同的编译器给出的定义可能不相同定义,不同的编译器给出的定义可能不相同