asアセンブリインフラストラクチャ設計--関数設計と関数スタックパラメータ問題


asアセンブリ関数設計:定義関数(プログラム注釈が面白いことを発見し、C言語用/××/,C++用//と/××/,python用#、アセンブリには多くの注釈があります:用#用;まだ役に立つ!
関数定義のフォーマット:
 .section .data              #        
     output:
         .asciz "The number is:%d
" # .section .text # .globl _start # _start _start: # movl $2, %ebx # 2 ebx call print_fun # print_fun movl $5, %ebx call print_fun # , 5 print_fun movl $12, %ebx call print_fun # movl $1, %eax movl $0, %ebx int $0x80 # exit .type print_fun, @function # ,.type print_fun ,@function print_fun: # pushl %ebx # ebx pushl $output # , call printf # C printf addl $8, %esp # ret #
     
実は上のポイントは.type print_fun,@functionは、関数を定義する方法であり、後に一般的に関数エントリアドレス識別子が続く.
関数パラメータの問題:
asアセンブリおよびC言語では、関数呼び出し時にパラメータを渡す基準はスタックを使用して動作しますが、ARMアセンブリなどの他のアセンブリはax、bxなどを介して、パラメータが4つ以上のパラメータを超える場合にスタックでスタックに転送されます.次のパラメータ問題をシミュレートします(3つのパラメータがあると仮定します):
1つ目のスキーム:まずパラメータ1から3を順番にスタックを押して、それから関数を呼び出して自動的に戻りアドレスを保存して、この時espは戻りアドレスを指します;
スタックハイアドレス:パラメータ3
パラメータ2
パラメータ1
スタックローアドレス:戻りアドレス<------esp
問題:関数内にもいくつかのデータを圧入する場合、espは変化します.それは、入力されたパラメータを使用する必要がある場合、espに基づいて取得するのは難しいです(espは各関数でデータを圧入するにつれて異なるためです).
第2の方案:上の問題を解決して、1つのebpを導入して、ebpを固定して1つの位置を指して、それではこの時espは正常で、関数の中で勝手にデータを圧入することができます;次のように表示されます.
movl%esp,%ebp#はebpをesp開始位置に指し示し、パラメータ1をとる場合は4(%ebp)を用いることができる.ebpのデフォルトはssをセグメントベースアドレスとして使用することに注意してください.
スタック高アドレス:パラメータ3 12(%ebp)
パラメータ2 8(%ebp)
パラメータ1 4(%ebp)
スタック低アドレス:戻りアドレス<--------esp==ebp問題:関数を呼び出す前にebpにバイト数を保存した場合、関数を終了した後にこのバイト数を使用する必要がある場合、問題が発生します.各関数が伝達するパラメータが異なるため,ebpが最初にどの位置にあるのか,どの値なのか全く分からない.
第3の方案:上の問題を解決して、先にebpの値をスタックに圧して、関数を脱退する時スタックをポップアップしてくれればいいです.
        pushl %ebp
        movl  %esp, %ebp
スタック高アドレス:パラメータ3 16(%ebp)
パラメータ2 12(%ebp)
パラメータ1 8(%ebp)
リターンアドレス4(%ebp)
スタック低アドレス:古いebp値<------esp==ebp
したがって、アセンブリ(C言語も)関数呼び出しパラメータフレームワークは(asアセンブリでは関数がこのフレームワークである)とまとめることができます.
pushl %ebp
movl %esp, %ebp	
...............
movl %ebp, %esp
popl %ebp
ret
上のフレームワークから分かるように、スタック伝達パラメータは、関数内部でpoplを介してパラメータをポップアップするのではなく、ebpを用いてスタック内のパラメータを間接的に使用する.最後に戻ると、パラメータはスタックに残ります.したがって、関数が呼び出された場合は、その関数が戻った後、スタック内のパラメータをクリーンアップすることを忘れないでください.poplでポップアップするかaddl$12,%esp(3パラメータ計12バイト)を使用して、espをパラメータ位置に押し込む前に戻すことができます.
上記の例によれば、スタックパラメータを使用して変更し、poplとaddlの2つの方法でスタックをバランスさせる.
.section .data
     output:
         .asciz "The number is:%d
" .section .text .globl _start _start: pushl $2 call print_fun addl $4, %esp pushl $5 call print_fun addl $4, %esp pushl $20 call print_fun popl %edx movl $1, %eax movl $0, %ebx int $0x80 .type print_fun, @function print_fun: pushl %ebp movl %esp, %ebp pushl 8(%ebp) pushl $output call printf addl $8, %esp movl %ebp, %esp popl %ebp ret
転載著者と原文の出所、原文の住所を明記してください.http://blog.csdn.net/yuzhihui_no1/article/details/42706871