汇编代码导致递归

deg*_*ion 2 c c++ x86 assembly

我一直在编写一个C应用程序,我需要x86汇编语言.我对汇编很新,下面的代码片段会导致递归:

unsigned int originalBP;
unsigned fAddress;
void f(unsigned short aa) {
    printf("Function %d\n", aa);
}

unsigned short xx = 77;
void redirect() {
    asm {
        pop originalBP
        mov fAddress, offset f
        push word ptr xx
        push fAddress
        push originalBP
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我打电话redirect,它会反复输出:"功能1135"

首先,以下是有关执行此代码的环境的一些信息:

  • 编写此代码以在NTVDM下执行
  • 使用微小的内存模型(所有段指针寄存器指向同一段)

这是我对上面代码应该做什么的期望(这很可能是错误的罪魁祸首):

  • 弹出堆栈并存储值originalBP; 我相信这个值实际上是当前函数的地址,即redirect
  • f参数值(值xx)推送到堆栈
  • 推送f堆栈的地址(因为只有一个段,只需要偏移)
  • 推回地址 redirect

当然,如果这是正确的流程,递归将是明显的(除了打印1135而不是7的部分).但有趣的是,对于没有参数的函数执行相同操作只会产生一行输出,即:

unsigned int originalBP;
unsigned fAddress;
void f() {
    printf("Function");
}


void redirect() {
    asm {
        pop originalBP
        mov fAddress, offset f
        push fAddress
        push originalBP
    }
}
Run Code Online (Sandbox Code Playgroud)

这可能意味着我对上述代码的理解是完全错误的.这段代码中的真正问题是什么?

编辑:我可能留下了一些未说明的事情:

  • 这是一个16位应用程序
  • 使用的编译器是Borland C++ 3.1,作为Eclipse插件
  • redirect从所谓mainredirect()

编辑(关于玛格丽特布鲁姆的回答)这是一个redirect被调用的指令执行的例子.括号中的值表示堆栈指针寄存器以及每个指令执行前该位置的值:

  • 呼叫重定向
  • (FFF4-04E6) push bp
  • (FFF2-FFF6) mov bp, sp
  • (FFF2-FFF6) mov fAddress, offest f
  • (FFF2-FFF6) pop originalBP
  • (FFF4-04E6) pop originalRIP
  • (FFF6-0000)push xx(我已将xx更改为1187)
  • (FFF4-0755) push originalRIP
  • (FFF2-04E6) push fAddress
  • (FFF0-04AC) push originalBP
  • (FFEE-FFF6) pop bp
  • (FFF0-04AC) ret
    • (f)(FFF2-04E6) push bp
    • (FFF0-FFF6) mov bp,sp
    • printf执行
    • (FFF0-FFF6) pop bp
    • (FFF2-04E6)ret 接下来的陈述似乎return 0;是主要的结尾.

执行继续通过一堆线,并以某种方式回到线路调用redirect.

Mar*_*oom 5

对于你的第二个片段,没有参数的片段,堆栈状态如下:

Where                 | Stack (growing on the left)
----------------------+----------------------------
after redirect prolog   redirect rip, redirect bp
pop originalBP          redirect rip
push fAddress           redirect rip, fAddress
push originalBP         redirect rip, fAddress, redirect bp
after redirect epilog   redirect rip, fAddress
after redirect return   redirect rip (control moved to f)
after f prolog          redirect rip, f bp
after f epilog          redirect rip
after f return          (control moved to redirect caller)
Run Code Online (Sandbox Code Playgroud)

其中redirect rip表示函数的返回地址(返回IP)redirect.

正如您所看到的,在f正确输入堆栈时redirect rip,返回地址为redirect.退出时,控件返回给redirect调用者.

对于您的第一个代码段,堆栈如下:

Where                 | Stack (growing on the left)
----------------------+----------------------------
after redirect prolog   redirect rip, redirect bp
pop originalBP          redirect rip
push word ptr xx        redirect rip, xx
push fAddress           redirect rip, xx, fAddress
push originalBP         redirect rip, xx, fAddress, redirect bp
after redirect epilog   redirect rip, xx, fAddress
after redirect return   redirect rip, xx (control moved to f)
after f prolog          redirect rip, xx, f bp
after f epilog          redirect rip, xx
after f return          (control moved to xx)
Run Code Online (Sandbox Code Playgroud)

f我们进入redirect rip, xx时,我们应该在堆栈上xx, redirect rip.
使用前一个配置,参数aa包含返回地址redirect和返回地址f的值是xx.


根据您对我的评论回答,代码意外循环.


如果要f使用参数调用,请确保在返回地址之前将它们推送:

pop originalBP
pop originalRIP

;Arguments go here    
push xx

push originalRIP
push fAddress
push originalBP
Run Code Online (Sandbox Code Playgroud)