【汇编实战】多重循环程序实验(一文学会)

系列文章目录

【汇编实战】多重循环程序实验(一文学会)


文章目录

  • 系列文章目录
  • 一、实验内容
  • 二、实验过程
    • 2.1 查看反汇编代码
    • 2.2 反汇编代码分析
    • 2.3 四重循环的汇编实现
      • 2.3.1 程序编写
      • 2.3.2 实验结果


一、实验内容

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

二、实验过程

2.1 查看反汇编代码

首先,我们使用C++编写四重循环代码,每重循环大小为10,在循环最内层对ans加一,预期答案为10000。
编写C++代码如下所示:

#include 
using namespace std;
int main(){
     
    int ans = 0;
    for(int i =0; i < 10; i++){
     
        for(int j = 0 ;j < 10; j++){
     
            for(int k =0 ; k< 10 ; k++){
     
                for(int h = 0; h < 10; h++){
     
                ans += 1;
                }
            }
        }
    }
    cout << ans << endl;
    return ans;
}

使用g++查看其汇编代码以及反汇编代码,分别运行如下命令行:

g++ -S .\triloop.cpp
g++ -g -c .\triloop.cpp
objdump -S triloop.o >triloop_dump.s

在文件夹下分别生成汇编文件triloop.s以及反汇编文件triloop_dump.s。本实验中我们通过查看反汇编代码triloop_dump.s分析每一行汇编代码的功能。

2.2 反汇编代码分析

上一小节中生成的汇编代码核心部分如下所示:

#include 
using namespace std;
int main(){
     
   0: 55                    push   %rbp
   1: 48 89 e5              mov    %rsp,%rbp
   4: 48 83 ec 40           sub    $0x40,%rsp
   8: e8 00 00 00 00        callq  d <main+0xd>
    int ans = 0;
   d: c7 45 fc 00 00 00 00  movl   $0x0,-0x4(%rbp)
    for(int i =0; i < 10; i++){
     
  14: c7 45 f8 00 00 00 00  movl   $0x0,-0x8(%rbp)
  1b: 83 7d f8 09           cmpl   $0x9,-0x8(%rbp)
  1f: 7f 43                 jg     64 <main+0x64>
        for(int j = 0 ;j < 10; j++){
     
  21: c7 45 f4 00 00 00 00  movl   $0x0,-0xc(%rbp)
  28: 83 7d f4 09           cmpl   $0x9,-0xc(%rbp)
  2c: 7f 30                 jg     5e <main+0x5e>
            for(int k =0 ; k< 10 ; k++){
     
  2e: c7 45 f0 00 00 00 00  movl   $0x0,-0x10(%rbp)
  35: 83 7d f0 09           cmpl   $0x9,-0x10(%rbp)
  39: 7f 1d                 jg     58 <main+0x58>
                for(int h = 0; h < 10; h++){
     
  3b: c7 45 ec 00 00 00 00  movl   $0x0,-0x14(%rbp)
  42: 83 7d ec 09           cmpl   $0x9,-0x14(%rbp)
  46: 7f 0a                 jg     52 <main+0x52>
                ans += 1;
  48: 83 45 fc 01           addl   $0x1,-0x4(%rbp)
                for(int h = 0; h < 10; h++){
     
  4c: 83 45 ec 01           addl   $0x1,-0x14(%rbp)
  50: eb f0                 jmp    42 <main+0x42>
            for(int k =0 ; k< 10 ; k++){
     
  52: 83 45 f0 01           addl   $0x1,-0x10(%rbp)
  56: eb dd                 jmp    35 <main+0x35>
        for(int j = 0 ;j < 10; j++){
     
  58: 83 45 f4 01           addl   $0x1,-0xc(%rbp)
  5c: eb ca                 jmp    28 <main+0x28>
    for(int i =0; i < 10; i++){
     
  5e: 83 45 f8 01           addl   $0x1,-0x8(%rbp)
  62: eb b7                 jmp    1b <main+0x1b>
                }
            }
        }
    }
    cout << ans << endl;
  64: 8b 45 fc              mov    -0x4(%rbp),%eax
  67: 89 c2                 mov    %eax,%edx
  69: 48 8b 0d 00 00 00 00  mov    0x0(%rip),%rcx        
# 70 
  70: e8 00 00 00 00        callq  75 <main+0x75>
  75: 48 8b 15 00 00 00 00  mov    0x0(%rip),%rdx        
# 7c 
  7c: 48 89 c1              mov    %rax,%rcx
  7f: e8 00 00 00 00        callq  84 <main+0x84>
    return ans;
  84: 8b 45 fc              mov    -0x4(%rbp),%eax
  87: 48 83 c4 40           add    $0x40,%rsp
  8b: 5d                    pop    %rbp
  8c: c3                    retq   

【分析】

Push %rbp
Mov %rsp,%rbp

Rbp是指向当前栈帧底部的基指针,rsp是指向当前栈顶部的栈帧顶部的指针
关于rbp和rsp的更多资料可以查看这篇博客https://blog.csdn.net/ABo_Zhang/article/details/89668046

Sub $0x40,%rsp

rsp的值减去了64,看似只是简单地修改了rsp寄存器的值,其实质确实给main函数的局部变量和临时变量预留了64字节的空间

callq  d <main+0xd> 

将下一条指令的CS和IP入栈,操作与call指令对应的jump指令

movl   $0x0,-0x4(%rbp)

rbp向下移动四个字节的位置存放ans,赋值为0

movl   $0x0,-0x8(%rbp)

rbp向下移动八个字节的位置存放i,赋值为0

cmpl   $0x9,-0x8(%rbp)
jg     64 <main+0x64>

比较i和9的大小,如果i > 9 跳到64,64执行cout<

movl   $0x0,-0xc(%rbp)
cmpl   $0x9,-0xc(%rbp)
jg     5e <main+0x5e> 

rbp向下移动12字节处存放j,赋值为0
比较j和9的大小,如果 j > 9 跳到5e

movl   $0x0,-0x10rbp)
cmpl   $0x9,-0x10rbp)
jg     58 <main+0x58> 

rbp向下移动16字节处存放k,赋值为0
比较k和9的大小,如果 k > 9 跳到58 。
h同理,省略。

addl   $0x1,-0x4(%rbp)

前面提到rbp向下移动四个字节的位置存放ans,这里执行ans+1

addl   $0x1,-0x14(%rbp)
jmp    42 <main+0x42>

如果不跳到52证明h < 9, h++
跳到42处继续比较h和9的大小

addl   $0x1,-0x10(%rbp)
jmp    35 <main+0x35>

K++,之后跳到35处继续比较k和9的大小。
后面j和i的处理过程类似,在此省略。

mov    -0x4(%rbp),%eax
add    $0x40,%rsp
pop    %rbp 
retq

将ans的值赋值给eax,rsp指向rbp的位置,将rbp推出栈帧。

2.3 四重循环的汇编实现

2.3.1 程序编写

编写四重循环汇编程序如下:

.386
.model flat, stdcall
option casemap : none
include		msvcrt.inc
includelib	msvcrt.lib

endl equ <0DH, 0AH>
.data
szFormat	db	"%d ", endl, 0

.code
main PROC
; mov	ecx, 10; 循环最多10次
xor esi, esi
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
loop1:	; 第一层循环
	mov	eax, 0
L4:	cmp eax, 9
	jg	endloop1
loop2:; 第二层循环
	mov	ebx, 0
L3:	cmp	ebx, 9;
	jg	endloop2
loop3:; 第三层循环
	mov	ecx, 0
L2:	cmp	ecx, 9;
	jg	endloop3
loop4: ; 第四层循环
	mov	edx, 0
L1:	cmp	edx, 9;
	jg	endloop4
	inc esi
	inc edx
	jmp L1
endloop4:
	inc ecx
	jmp L2
endloop3:
	inc ebx
	jmp L3
endloop2:	
	inc eax
	jmp L4

endloop1:
	invoke	crt_printf , addr szFormat, esi;输出ans
	ret
main endp
END  main

2.3.2 实验结果

运行上述程序得到如下结果,实验结果与预期相同。

【汇编实战】多重循环程序实验(一文学会)_第1张图片

你可能感兴趣的:(汇编)