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

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

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指向的指令地址继续执行,也即方法调用指令的下一条指令继续开始。但是不得不说栈内存区域有点紊乱啊,不知道为啥......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值