Search code examples
assemblyx86gnu-assembler

Wrong return in assembler function (x86)


I use Intel x86 for assembler programming. I've got two variables (int), and I want the assembler function to return the biggest. I call the assembler function with a C program, and I've got this in the main(), function(1,5).

Here is the assembler code:

            .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

The biggest number will be in %eax (movl var2, %eax). The problem is that the function always returns the initial number in %eax. For example, function(1,5) returns "1" instead of "5".

I don't understand why the result is wrong.

EDIT : Thanks to your replies, I've modified the program thanks to your advice :

  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

To come-back in function(), I use jmp, is it correct? It works fine.

Also, how can I improve this code? I use variables because the aim will be to have three numbers and find the median one.


Solution

  • I think you're confused about what the jg and jl instructions are doing.

    From your code, my best guess is that you're thinking of them as being approximately equivalent to this C code:

    if (condition) cond1();
    

    whereas they actually behave like

    if (condition) goto cond1;
    

    So, there are three possible control flow paths through your function:

    1) If the jg branch is taken:

    ----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) If the jg branch is not taken, but the jl branch is taken:

    ----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) If neither branch is taken -- this is the only path which executes 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----'