Неправильный возврат в ассемблерной функции (x86) - PullRequest
2 голосов
/ 12 ноября 2011

Я использую 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.Например, функция (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 ]

2 голосов
/ 12 ноября 2011

Я думаю, вы не понимаете, что делают инструкции jg и jl.

Исходя из вашего кода, я думаю, что вы думаете о них как о приблизительно эквивалентных этому.Код 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 голос
/ 12 ноября 2011

Значение, возвращаемое функцией, обычно возвращается в регистр 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
1 голос
/ 12 ноября 2011

Ну, я не очень знаком с форматом NASM (я использую MASM ), и я не делал сборку x86 некоторое время, но она не выглядит как будто вы что-то возвращаете из своих функций (я полагаю, cdecl соглашение о вызовах). Вам нужно поместить возвращаемое значение в стек, а затем выполнить «ret 4» или что-то в этом роде.

...