3

アセンブラーのプログラミングには Intel x86 を使用しています。2 つの変数 (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) は "5" ではなく "1" を返します。

結果が間違っている理由がわかりません。

編集:あなたの返信のおかげで、私はあなたのアドバイスのおかげでプログラムを修正しました:

  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 つの数値を持ち、中央値を見つけることだからです。

4

3 に答える 3

4

jgjl命令が何をしているのか混乱していると思います。

あなたのコードから、あなたはそれらをこの C コードとほぼ同等であると考えていると思います。

if (condition) cond1();

一方、実際には次のように動作します

if (condition) goto cond1;

したがって、関数を介して 3 つの可能な制御フロー パスがあります。

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 に答える