`

从汇编和寄存器层面,简单描述下方法调用的时候都发生了什么

    博客分类:
  • asm
阅读更多

        先看一个简单的汇编程序:

assume cs:code,ss:stack
stack segment
	dw 10 dup('a')
stack ends
code segment
start:
	mov ax,stack
	mov ss,ax
	mov sp,20

	mov ax,1
	mov cx,4
	call s
	mov ax,4c00h
	int 21h
  s:
	add ax,ax
	loop s
	ret 
code ends
end start

         自定义一个stack段,然后产生一次方法调用,用ms的debug工具单步调试,可以看到编译后的代码里边s这个标号变成了offset:

-u
0B55:0000 B8530B        MOV     AX,0B53
0B55:0003 8ED0          MOV     SS,AX
0B55:0005 BC1400        MOV     SP,0014
0B55:0008 B80100        MOV     AX,0001
0B55:000B B90400        MOV     CX,0004
0B55:000E E80500        CALL    0016
0B55:0011 B8004C        MOV     AX,4C00
0B55:0014 CD21          INT     21
0B55:0016 03C0          ADD     AX,AX
0B55:0018 E2FC          LOOP    0016
0B55:001A C3            RET

         call s在编译后对应的指令是:

0B55:000E E80500        CALL    0016

         前边表示内存单元,即调试的时候把程序加载到了0b55:0开始的内存区域,而call s对应的机器码在0b55 * 16 + E的地方,E80500表示call s指令编译后的机器码,E8表示call指令,0500是s标号编译后的地址,由于call实际上等同于是call near ptr s,而near编译后是两个字节的值。而这里的5是offset,而不是绝对地址,call 后边的0016是根据call s下一条指令的地址0b55:0011加上这个offset计算出来的,也就是0b55:0016,由于call near ptr s是段内转移,所以段地址不变,即0b55,只显示0011了。

        另外,从内存单元的机器码和其对应的汇编指令看,mov ax stack被编译成了:

0B55:0000 B8530B        MOV     AX,0B53
         即在0b53:0的位置,应该是我们栈的内存区域(为了更明显起见,我用dw 10 dup('a')初始化的栈内存区):
-d 0b53:0
0B53:0000  61 00 61 00 61 00 61 00-61 00 61 00 61 00 61 00   a.a.a.a.a.a.a.a.
0B53:0010  61 00 61 00 00 00 00 00-00 00 00 00 00 00 00 00   a.a.............
0B53:0020  B8 53 0B 8E D0 BC 14 00-B8 01 00 B9 04 00 E8 0D   .S..............
         从0b53:0开始的16个word,word用两个字节存放,高字节存放在高地址,低字节存放在低地址,用word表示的a,是0061,按地址顺序存放后就成了6100了。

        在开始执行前,先看下寄存器的信息:

-r
AX=0000  BX=0000  CX=0043  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B43  ES=0B43  SS=0B53  CS=0B55  IP=0000   NV UP EI PL NZ NA PO NC
        执行前两条条指令后,ss已经指向了0b53:
-t
AX=0B53  BX=0000  CX=0043  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B43  ES=0B43  SS=0B53  CS=0B55  IP=0003   NV UP EI PL NZ NA PO NC
       在执行call s之前,可以看到sp=0014,stack区域的数据却好像被什么改变了:
-t
AX=0001  BX=0000  CX=0004  DX=0000  SP=0014  BP=0000  SI=0000  DI=0000
DS=0B43  ES=0B43  SS=0B53  CS=0B55  IP=000E   NV UP EI PL NZ NA PO NC
-d 0b53:0
0B53:0000  61 00 61 00 61 00 61 00-61 00 53 0B 00 00 08 00   a.a.a.a.a.S.....
0B53:0010  55 0B 57 05 00 00 00 00-00 00 00 00 00 00 00 00   U.W.............
         不过无妨,看看call之后,sp值减小了2,也就是往栈里压入了一个word:
-t
AX=0001  BX=0000  CX=0004  DX=0000  SP=0012  BP=0000  SI=0000  DI=0000
DS=0B43  ES=0B43  SS=0B53  CS=0B55  IP=0016   NV UP EI PL NZ NA PO NC

         这个word的只是多少呢?从stack的内存区域0b53:0013地址可以看到,是0011,其实呢也就是call s下一条指令的地址!由此我们可以知道方法调用的时候,会把方法调用指令后边那条指令的地址压入栈中:

-d 0b53:0
0B53:0000  61 00 61 00 61 00 61 00-01 00 00 00 16 00 55 0B   a.a.a.a.......U.
0B53:0010  57 05 11 00 00 00 00 00-00 00 00 00 00 00 00 00   W...............

         那什么时候会弹出呢?猜猜也是方法调用返回的时候!即ret指令执行的时候,sp增加了2,即弹出了栈里边存的值,并把弹出来的值赋给了ip寄存器。被调用方法里边执行ret指令后的寄存器信息和栈内存区域:

-t
AX=0010  BX=0000  CX=0000  DX=0000  SP=0014  BP=0000  SI=0000  DI=0000
DS=0B43  ES=0B43  SS=0B53  CS=0B55  IP=0011   NV UP EI PL NZ AC PO NC
-d 0b53:0
0B53:0000  61 00 61 00 61 00 61 00-10 00 10 00 00 00 11 00   a.a.a.a.........
0B53:0010  55 0B 57 05 00 00 00 00-00 00 00 00 00 00 00 00   U.W.............

         ret后,从ip指向的指令地址继续执行,也即方法调用指令的下一条指令继续开始。但是不得不说栈内存区域有点紊乱啊,不知道为啥......

分享到:
评论

相关推荐

    汇编语言课程设计——调用系统时间

    4. 遇到的问题及解决方法:分享在实现过程中遇到的挑战和如何克服它们,可能是关于中断处理、寄存器使用或其他汇编语言相关的难点。 5. 结果分析:总结项目成果,可能包括最终程序的时间显示效果,以及对汇编语言...

    从汇编角度分析C语言的过程调用

    在深入理解C语言的过程调用机制之前...通过这些汇编层面的深入分析,我们可以更好地理解C语言编译后程序的执行流程和内存布局。这不仅对于学习C语言和系统编程是非常有帮助的,也有助于我们编写更高效、更安全的代码。

    ARM汇编 C语言 C++ 相互调用

    这些知识点涵盖了ARM汇编语言与C语言、C++之间相互调用的多个层面,包括程序间的接口设计、链接约定的理解和应用,以及在具体编程实践中的注意事项。掌握这些知识点对于进行底层编程、嵌入式系统开发以及混合编程...

    从汇编语言到Windows内核编程_Windows编程_

    《从汇编语言到Windows内核编程》是深入探讨Windows操作系统内部机制的权威之作,尤其适合对计算机系统底层有浓厚兴趣或需要进行系统级开发的读者。这本书将带领读者从最基本的汇编语言出发,逐步过渡到复杂的...

    x64汇编编程书籍

    - **函数理解:** 在汇编语言层面理解函数调用机制。 - **输入输出缓冲:** 学习如何在低级别实现输入输出缓冲机制。 - **编译器作用域:** 理解编译器如何处理变量的作用域。 - **多处理概念介绍:** 介绍多核...

    Linux下的系统调用和进程

    ### Linux下的系统调用与进程深入解析 #### 系统调用:Linux核心与应用程序间的桥梁 系统调用是Linux操作系统中,用户空间的应用程序与内核之间进行交互的主要方式。它提供了应用程序能够请求内核服务的一系列接口...

    DSP汇编除法程序

    在该示例中,我们不仅可以看到基本的除法运算实现过程,还能了解到如何通过汇编语言进行数据存储和调用链接文件等高级操作。 #### 二、关键概念解析 ##### 1. DSP汇编语言简介 DSP汇编语言是为DSP处理器设计的一种...

    Windows环境下32位汇编语言程序设计(第2版)

    《Windows环境下32位汇编语言程序设计(第2版)》是一本深入探讨在Windows操作系统下使用32位汇编语言进行程序开发的专业教程。汇编语言是计算机科学的基础,它是一种低级编程语言,直接对应于机器的指令集,使得...

    arm汇编语言编写

    从给定的文件信息来看,我们正在探讨的主题是“ARM汇编语言编写”,这涉及到ARM架构下的汇编语言编程,特别是针对Cortex系列处理器。该主题不仅覆盖了基础的汇编语言概念,还深入到了ARM架构的具体细节,包括条件...

    汇编语言指令大全(详解版)

    例如,PUSHF(保存标志寄存器到堆栈)和POPF(从堆栈恢复标志寄存器),用于在函数调用前后保存和恢复CPU的状态标志。 四、指令优化技巧 了解和掌握汇编语言指令的优化技巧,对于提高程序的运行效率至关重要。这...

    Linux汇编语言AT&T开发指南

    Linux汇编语言AT&T开发指南涵盖了多种编程和系统开发中不可或缺的知识点,特别是对于在Linux环境下开发与底层硬件交互的程序。本指南详细介绍了AT&T汇编语法和指令的使用方法,下面将基于提供的内容点,逐一详细讲解...

    x86汇编语言-从实模式到保护模式 配套源码及资料

    在这一模式下,程序员可以自由地操作寄存器和内存,这使得它成为学习x86汇编语言入门的必经之路。实模式下的汇编编程,虽然缺乏保护机制,却能帮助程序员深入理解CPU的工作机制和内存管理的基本概念。 随着技术的...

    汇编语言基础教学

    汇编语言的学习不仅要求对基本概念有深入的理解,还要求掌握具体的指令集和数据表示方法。通过实践编写简单的汇编语言程序,可以帮助加深对这些概念的理解,并熟悉8086处理器的工作机制。此外,堆栈管理和存储器分段...

    Inter 汇编架构分析

    综上所述,Intel汇编架构分析涵盖了汇编语言的基本概念、寻址模式、寄存器使用、指令流水线、程序优化以及操作系统层面的机制。理解这些知识点对于深入理解计算机系统的工作原理和编写高性能代码至关重要。

    汇编语言复习要点(言简意赅)

    标题与描述强调了汇编语言复习的关键点,涵盖了计算机原理、数与指令的理解、存储器寻址、堆栈操作、指令集以及程序框架等多个方面。下面是对这些知识点的详细解析: ### 一、程序员眼中的计算机 #### 计算机原理...

    IBM PC 汇编pdf格式

    汇编语言是计算机硬件层面的低级编程语言,它直接对应于机器指令,对理解计算机工作原理和优化程序性能至关重要。这本书详细介绍了IBM PC架构下的汇编语言知识,适合初学者和有经验的程序员进一步提升技能。 在学习...

    keil调试教程 反汇编技巧经验 ARM汇编指令.rar

    学习ARM汇编,不仅需要了解每条指令的语法和功能,还需要理解其在硬件层面的执行过程,比如寄存器的使用和流水线机制。 在实际调试过程中,我们可能遇到如下的场景:当C代码中的函数运行异常时,可以通过反汇编查看...

    罗云彬的win32下汇编语言程序设计(电子版)

    本书首先从基础的汇编语言语法讲起,包括寄存器的使用、指令系统以及基本的数据类型。然后,它将带领读者进入Win32汇编的世界,讲解如何编写与Windows操作系统交互的程序,如创建窗口、处理消息、内存管理等。书中会...

    叫大家轻松汇编语言教程

    虽然学习汇编语言对于初学者来说可能会觉得难度较大,但只要掌握正确的学习方法,理解其基本原理和结构,你会发现其实汇编语言的学习也可以变得相对轻松。 **汇编语言的特点** 1. **直接性**:汇编语言的指令直接...

Global site tag (gtag.js) - Google Analytics