3

我使用 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 中的初始数字。例如,function(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,是否正确?它工作正常。

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

4

3 回答 3

4

我认为您对jgandjl指令的作用感到困惑。

从您的代码中,我最好的猜测是您认为它们与此 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----'
于 2011-11-11T21:15:31.290 回答
2

从函数返回的值通常在 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
于 2011-11-11T23:04:28.407 回答
1

好吧,我对NASM格式不是很熟悉(我使用MASM),而且我有一段时间没有进行 x86 汇编了,但看起来你并没有从你的函数中返回任何东西(我假设是cdecl调用约定) . 您需要将返回值推入堆栈,然后执行“ret 4”或类似的操作。

于 2011-11-11T20:16:47.717 回答