汇编语言实验——反汇编(矩阵乘法)

3.1 实验内容

C语言编写多重循环程序(大于3重),查看其反汇编码,分析各条语句功能(分析情况需要写入实验报告),并采用汇编语言重写相同功能程序。

3.2实验环境

Microsoft Visual Studio 2017+masm 32

3.3实验步骤

3.3.1 编写c语言代码

此处我选择的程序为实现两个矩阵相乘,是一个3重循环的程序。

3.3.2 查看反汇编代码并分析

  1: #include<stdio.h>
    2: 
    3: int Result[10][10];
    4: int MatrixA[10][2] = { 1,2,3,4,5,6,7,8,9,23,24,46,68,23,45,66,32,65,45,24 };
    5: int MatrixB[2][10] = { 23,45,23,12,43,2,5,6,43,24,12,45,33,22,64,55,23,45,24,23 };
    6: 
    7: int main()
    8: {
00B91810  push        ebp 
//将前栈底指针压入栈中
00B91811  mov         ebp,esp
//ebp存入当前esp的值  
00B91813  sub         esp,0FCh  
//更新esp的值,预留出0FCh个单位的地址空间
00B91819  push        ebx  
//将原始内存偏移指针压栈
00B9181A  push        esi  
//将源地址指针压栈
00B9181B  push        edi  
//将目的地址指针压栈
00B9181C  lea         edi,[ebp-0FCh]  
//将栈顶指针赋给edi
00B91822  mov         ecx,3Fh  
//ecx存储重复次数3Fh次
00B91827  mov         eax,0CCCCCCCCh  
//将栈中从[ebp-0FCh]开始位置向高地址方向赋值0xCCCCCCCCh
00B9182C  rep stos    dword ptr es:[edi]  
//rep指示重复ecx中值的次数,stos指令的作用是将eax中的值拷贝到es:[edi]指向的位置
00B9182E  mov         ecx,offset _D5DA6D57_main@cpp (0B9C003h)  
00B91833  call        @__CheckForDebuggerJustMyCode@4 (0B91212h)  
    9:for (int i = 0; i < 10; i++)
;-----------------------------------------
00B91838  mov         dword ptr [ebp-8],0  
00B9183F  jmp         main+3Ah (0B9184Ah)  
//将i赋值为0,由于i是局部变量,所以存储在栈中。
//无条件跳转到判断模块,原因是第一次不需要增加后再判断
;-------------------------------------------
00B91841  mov         eax,dword ptr [ebp-8]  
00B91844  add         eax,1  
00B91847  mov         dword ptr [ebp-8],eax  
//将i赋给eax,执行加1操作,再赋给i
;---------------------------------------------
00B9184A  cmp         dword ptr [ebp-8],0Ah  
00B9184E  jge         main+0B1h (0B918C1h)  
//判断i是否大于等于10,大于等于10则跳转到循环结束处。
    10:{
    11:     for (int j = 0; j < 10; j++)
;------------------------------------------
00B91850  mov         dword ptr [ebp-14h],0  
00B91857  jmp         main+52h (0B91862h)  
;-------------------------------------------
00B91859  mov         eax,dword ptr [ebp-14h]  
00B9185C  add         eax,1  
00B9185F  mov         dword ptr [ebp-14h],eax  
;--------------------------------------------
00B91862  cmp         dword ptr [ebp-14h],0Ah  
00B91866  jge         main+0AFh (0B918BFh)  
//与i相同
    12:{
    13:     for (int k = 0; k < 2; k++)
;-------------------------------------------
00B91868  mov         dword ptr [ebp-20h],0  
00B9186F  jmp         main+6Ah (0B9187Ah)  
;---------------------------------------------
00B91871  mov         eax,dword ptr [ebp-20h]  
00B91874  add         eax,1  
00B91877  mov         dword ptr [ebp-20h],eax  
;---------------------------------------------
00B9187A  cmp         dword ptr [ebp-20h],2  
00B9187E  jge         main+0ADh (0B918BDh)  
;---------------------------------------------
//与i相同
    14:             {
    15:                 Result[i][j] += MatrixA[i][k] * MatrixB[k][j];
00B91880  imul        eax,dword ptr [ebp-8],28h  
//eax=i*40,因为是dword数组,所以4个偏移量代表一个数据,i*40代表Result的第i行开始的地址
00B91884  mov         ecx,dword ptr [ebp-20h]  
//ecx=k
00B91887  shl         ecx,2  
//ecx=4k,4个偏移量代表一个数据
00B9188A  imul        edx,dword ptr [ebp-20h],28h  
//edx=k*40,同i类似,表示MatrixB的第k行地址
00B9188E  mov         esi,dword ptr [ebp-8]  
//esi=i
00B91891  mov         edi,dword ptr [ebp-14h]  
//edi=j
00B91894  mov         ecx,dword ptr MatrixA (0B9A000h)[ecx+esi*8]  
//ecx=MatrixA[i][k],esi*8是因为MatrixA一行有两个数据,一个数据为4个偏移量,表示MatrixA的第i行,ecx=4k,表示第k个数据,4也为偏移量
00B9189B  imul        ecx,dword ptr MatrixB (0B9A050h)[edx+edi*4]  
//ecx=ecx*Matrix[k][j],edx=k*40表示MatrixB第k行的起始地址,edi=j,4j表示第j个数据。
00B918A3  mov         edx,dword ptr [ebp-14h]  
//edx=j
00B918A6  add         ecx,dword ptr Result (0B9A1F8h)[eax+edx*4]  
//ecx=ecx+Result[i][j],eax为Result的第i行其实地址,edx*4表示第j个数据
00B918AD  imul        eax,dword ptr [ebp-8],28h  
//eax=i*40
00B918B1  mov         edx,dword ptr [ebp-14h]  
//edx=j
00B918B4  mov         dword ptr Result (0B9A1F8h)[eax+edx*4],ecx  
//Result[i][j]=ecx,存储结果
    16:             }
00B918BB  jmp         main+61h (0B91871h)  
//第3重循环结束,跳转到k++
    17:         }
00B918BD  jmp         main+49h (0B91859h)  
//第2重循环结束,跳转到j++
    18:     }
00B918BF  jmp         main+31h (0B91841h)  
//第1重循环结束,跳转到i++
19:     for (int i = 0; i < 10; i++)
;-----------------------------------------------------
00B918C1  mov         dword ptr [ebp-2Ch],0  
00B918C8  jmp         main+0C3h (0B918D3h)  
//将i赋值为0,由于i是局部变量,所以存储在栈中。
//无条件跳转到判断模块,原因是第一次不需要增加后再判断
;-----------------------------------------------------
00B918CA  mov         eax,dword ptr [ebp-2Ch]  
00B918CD  add         eax,1  
00B918D0  mov         dword ptr [ebp-2Ch],eax  
//将i赋给eax,执行加1操作,再赋给i
;-----------------------------------------------------
00B918D3  cmp         dword ptr [ebp-2Ch],0Ah  
00B918D7  jge         main+10Eh (0B9191Eh)  
//判断i是否大于等于10,大于等于10则跳转到循环结束处。
    20:     {
21:         for (int j = 0; j < 10; j++)
;-------------------------------------------
00B918D9  mov         dword ptr [ebp-38h],0  
00B918E0  jmp         main+0DBh (0B918EBh)  
;-----------------------------------------------
00B918E2  mov         eax,dword ptr [ebp-38h]  
00B918E5  add         eax,1  
00B918E8  mov         dword ptr [ebp-38h],eax  
;---------------------------------------------
00B918EB  cmp         dword ptr [ebp-38h],0Ah  
00B918EF  jge         main+0FFh (0B9190Fh)  
//同i
    22:         {
23:             printf("%d ", Result[i][j]);
00B918F1  imul        eax,dword ptr [ebp-2Ch],28h  
//eax=i*40
00B918F5  mov         ecx,dword ptr [ebp-38h]  
//ecx=j
00B918F8  mov         edx,dword ptr Result (0B9A1F8h)[eax+ecx*4]  
//edx=Result[i][j]
00B918FF  push        edx  
//将edx压栈
00B91900  push        offset string "%d " (0B97B30h)  
//将"%d "压栈
00B91905  call        _printf (0B9104Bh)  
//调用_printf,输出edx
00B9190A  add         esp,8  
//栈顶指针加8,刚好压入两个变量,所以esp+8清栈
    24:         }
00B9190D  jmp         main+0D2h (0B918E2h)  
//内层循环结束,跳转j++
    25:         printf("\n");
00B9190F  push        offset string "\n" (0B97B34h)  
00B91914  call        _printf (0B9104Bh)  
00B91919  add         esp,4  
//同上_printf
    26:     }
00B9191C  jmp         main+0BAh (0B918CAh)  
//第一层循环结束,跳转i++
    27:     return 0;
00B9191E  xor         eax,eax  
//eax清0,return 0
28: }
00B91920  pop         edi  
//恢复原来调用的edi
00B91921  pop         esi  
//恢复原来调用的esi
00B91922  pop         ebx  
//恢复原来调用的ebx
00B91923  add         esp,0FCh  
//栈顶指针回退0FCh个地址单元
00B91929  cmp         ebp,esp  
00B9192B  call        __RTC_CheckEsp (0B9121Ch)  
00B91930  mov         esp,ebp
//将当前ebp赋给esp  
00B91932  pop         ebp 
//恢复原来的ebp 
00B91933  ret 

3.3.3 汇编代码实现矩阵的乘法

;定义所需的变量 
.data
Result dword 100 dup(0)
MatrixA dword 20 dup(1,2,3,4,5,6,7,8,9,23,24,46,68,23,45,66,32,65,45,24)
MatrixB dword 20 dup(23,45,23,12,43,2,5,6,43,24,12,45,33,22,64,55,23,45,24,23)
output byte "%d ",0
endl byte " ",0AH,0
.code
main Proc
;声明局部变量i,j,k
    local i,j,k
;i=0
    mov i,0
;无条件跳转L2,原因是第一次不需要增加后再判断
    jmp L2
;L1为i++
L1:
    mov eax,i
    add eax,1
    mov i,eax
;L2为比较i是否大于等于10,大于等于跳转
L2:
    cmp i,10
    jge L10
;L3为将令j=0,且无条件跳转L5,同i
L3:
    mov j,0
    jmp L5
;L4为j++
L4:
    mov eax,j
    add eax,1
    mov j,eax
;L5为比较j是否大于等于10,大于等于跳转到i++
L5:
    cmp j,10
    jge L1
;L6为令k=0,无条件跳转L8,同i
L6:
    mov k,0
    jmp L8
;L7为k++
L7:
    mov eax,k
    add eax,1
    mov k,eax
;L8为比较k是否大于等于2,大于等于跳转到j++
L8:
    cmp k,2
    jge L4
L9:
;eax=i*40,因为是dword数组,所以4个偏移量代表一个数据,i*40代表Result的第i行开始的地址
    imul eax,i,40
;将第i行Result的开始地址赋给ecx
    lea ecx,dword ptr Result[eax]
;edx=i*8,表示MatrixA的第i行
    imul edx,i,8
;将MatrixA第i行的起始地址赋给eax
    lea eax,dword ptr MatrixA[edx]
;edx=k*40,表示MatrixB的第k行数据
    imul edx,k,40
;将MatrixB第k行的起始地址赋给edx
    lea edx,dword ptr MatrixB[edx]
;esi=k
    mov esi,k
;edi=j
    mov edi,j
;eax=MatrixA[i][k],比例变址寻址
    mov eax,dword ptr[eax+esi*4]
;eax=eax*MatrixB[k][j]
    imul eax,dword ptr[edx+edi*4]
;edx=j
    mov edx,j
;eax=eax+Result[i][j]
    add eax,dword ptr[ecx+edx*4]
;Result[i][j]=eax
    mov dword ptr[ecx+edx*4],eax
;最内层循环结束,跳转k++
    jmp L7

;L10为令i=0,并且无条件跳转到判断处
L10:
    mov i,0
    jmp L12
;L11为输出换行并且i++
L11:
    invoke printf,offset endl
    mov eax,i
    add eax,1
    mov i,eax
;L12为比较i是否大于等于10,大于等于跳转到循环结束处
L12:
    cmp i,10
    jge L17
;L13为令j=0,并且无条件跳转到判断
L13:
    mov j,0
    jmp L15
;L14为j++
L14:
    mov eax,j
    add eax,1
    mov j,eax
;L15为比较j是否大于等于10,大于等于则循环结束,跳转到外层i++
L15:
    cmp j,10
    jge L11
L16:
;eax=i*40,表示Result第i行数据
    imul eax,i,40
;将Result第i行起始地址赋给ecx
    lea ecx,dword ptr Result[eax]
;edx=j
    mov edx,j
;ebx=Result[i][j]
    mov ebx,dword ptr[ecx+edx*4]
;调用输出函数,输出Result[i][j]
    invoke printf,addr output,ebx
;一次循环结束,跳转j++
    jmp L14
;L17为return 0并且返回
L17:
    xor eax,eax
    ret

3.4实验结果

c语言运行结果

汇编语言运行结果

 3.5完整代码

Chris_William/BIT-X86-Experiment (gitee.com)https://github.com/chris-william0829/bit-x86-experiment

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值