【问题标题】:Wrong return in assembler function (x86)汇编程序函数中的错误返回 (x86)
【发布时间】:2011-11-11 20:06:54
【问题描述】:

我使用 Intel x86 进行汇编程序编程。我有两个变量(int),我希望汇编函数返回最大的。我用一个 C 程序调用汇编函数,我在 main(), function(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,对吗? 它工作正常。

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

【问题讨论】:

  • 你正在比较堆栈上传递的参数,但从全局变量返回值

标签: assembly x86 gnu-assembler


【解决方案1】:

我认为您对 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----'

【讨论】:

  • GAS 语法使比较更加混乱,因为顺序颠倒了
【解决方案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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 它看起来不像nasm 语法(所以我删除了标签);它看起来像 gas,这意味着它很可能是 Linux,它的调用约定被正确使用。
    猜你喜欢
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    • 2020-09-23
    • 2014-07-19
    • 1970-01-01
    相关资源
    最近更新 更多