汇编程序函数返回错误(x86)

时间:2011-11-11 20:06:54

标签: assembly x86 gas

我使用Intel x86进行汇编编程。我有两个变量(int),我希望汇编程序函数返回最大值。我用C程序调用汇编程序函数,我在main()函数(1,5)中得到了它。

这是汇编代码:

            .globl function

            .data
var1:       .long 0
var2:       .long 0

            .text
function:
            movl    4(%esp), %eax
            movl    8(%esp), %ebx

            cmp     %eax, %ebx
            jg      cond1          /*greater, if a < b */
            jl      cond2          /*lower, if a > b */

            movl    var2, %eax

            ret

cond1:
            movl    %eax, var1     /*var1 = a */
            movl    %ebx, var2     /*var2 = b */
            ret


cond2:
            movl    %eax, var2     /*var2 = a*/
            movl    %ebx, var1     /*var1 = b */
            ret

最大的数字将是%eax(movl var2,%eax)。问题是 该函数始终返回%eax中的初始数字。 例如,函数(1,5)返回“1”而不是“5”。

我不明白为什么结果出错了。

编辑:感谢您的回复,我已根据您的建议修改了该计划:

  function:
            movl    4(%esp), %eax
            movl    8(%esp), %ebx

            cmp     %eax, %ebx
            jg      cond1          /*greater, if a < b */
            jl      cond2          /*lower, if a > b */
            next:
            movl    var2, %eax
            ret

cond1:
            movl    %eax, var1     /*var1 = a */
            movl    %ebx, var2     /*var2 = b */
            jmp     next

cond2:
            movl    %eax, var2     /*var2 = a*/
            movl    %ebx, var1     /*var1 = b */
            jmp     next

要回到function(),我使用jmp,这是正确的吗? 它工作正常。

另外,我该如何改进此代码?我使用变量,因为目标是有三个数字并找到中位数。

3 个答案:

答案 0 :(得分:2)

我认为您对jgjl说明正在做什么感到困惑。

从你的代码中,我最好的猜测是你认为它们大致相当于这个C代码:

if (condition) cond1();

而他们实际上表现得像

if (condition) goto cond1;

因此,您的函数有三种可能的控制流路径:

1)如果采用jg分支:

----caller----.
              |
              v

function:
             movl   4(%esp), %eax
             movl   8(%esp), %ebx

             cmp        %eax, %ebx   
             jg         cond1            /*greater, if a < b */

              |
           branch 
              |
              v

cond1:
             movl       %eax, var1             /*var1 = a */
             movl       %ebx, var2             /*var2 = b */
             ret

              |
   return to  |
<---caller----'

2)如果未采用jg分支,但采用jl分支:

----caller----.
              |
              v

function:
             movl   4(%esp), %eax
             movl   8(%esp), %ebx

             cmp        %eax, %ebx   
             jg         cond1            /*greater, if a < b */
             jl         cond2                   /*lower, if a > b */

              |
           branch 
              |
              v

cond2:
             movl       %eax, var2            /*var2 = a*/
             movl       %ebx, var1            /*var1 = b */
             ret

              |
   return to  |
<---caller----'

3)如果两个分支都没有 - 这是执行movl var2, %eax的唯一路径:

----caller----.
              |
              v

function:
             movl   4(%esp), %eax
             movl   8(%esp), %ebx

             cmp        %eax, %ebx   
             jg         cond1            /*greater, if a < b */
             jl         cond2                   /*lower, if a > b */

             movl       var2, %eax

             ret

              |
   return to  |
<---caller----'

答案 1 :(得分:1)

好吧,我不是很熟悉NASM格式(我使用MASM),而且我有一段时间没有完成x86程序集,但看起来你回来的样子并不像你的函数中的任何东西(cdecl调用约定我假设)。您需要将返回值推送到堆栈,然后执行“ret 4”或类似的操作。

答案 2 :(得分:1)

函数返回的值通常在EAX寄存器中返回,在您加载它之后,它永远不会改变(只更改“var1”和“var2”)。

对于简化版本(没有“var1”和“var2”):

function:
             movl   4(%esp), %eax      /* EAX = a                         */
             cmpl   8(%esp), %eax      /* Is a >= b?                      */
             jge done                  /*  yes, return a (already in EAX) */
             movl   8(%esp), %eax      /*  no, return b                   */
done:
             ret