Question

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.

Was it helpful?

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----'

OTHER TIPS

The value returned from the function is typically returned in the EAX register, which in your case never changes after you load it (you only change "var1" and "var2").

For a simplified version (without "var1" and "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

Well, I'm not very familiar with the NASM format (I use MASM), and I haven't done x86 assembly in a while, but it does not look like you are returning anything from your functions (cdecl calling convention I assume). You need to push the return value on to the stack and then do "ret 4" or something like that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top