2017-12-06 53 views
1

私に悩まされる1つの質問があります。なぜアセンブリx86_64 syscallのパラメータはi386のようにアルファベット順ではありません

そう... x86_32は私が感じるのレジスタで渡されパラメータににあるアルファベット順にeaxecxedxesi)と順にランクなぜ(esiediを、ebp

+---------+------+------+------+------+------+------+ 
| syscall | arg0 | arg1 | arg2 | arg3 | arg4 | arg5 | 
+---------+------+------+------+------+------+------+ 
| %eax | %ebx | %ecx | %edx | %esi | %edi | %ebp | 
+---------+------+------+------+------+------+------+ 

section .text 
    global _start 
_start: 
    mov eax, 1  ; x86_64 opcode for sys_exit 
    mov ebx, 0  ; first argument 
    int 0x80 

x86_64版でシステムコールのパラメータはパスですが少しランダムが配置さを見て、レジスタに編:

+---------+------+------+------+------+------+------+ 
| syscall | arg0 | arg1 | arg2 | arg3 | arg4 | arg5 | 
+---------+------+------+------+------+------+------+ 
| %rax | %rdi | %rsi | %rdx | %r10 | %r8 | %r9 | 
+---------+------+------+------+------+------+------+ 

section .text 
    global _start 
_start: 
    mov eax, 1  ; x86_64 opcode for sys_exit 
    mov edi, 0  ; first argument 
    syscall 

彼らは、特定の理由であることをしましたか?私はここに何か見ていないのですか?

+1

x86-64では、これは関数呼び出し規約と一致し、syscallラッパー関数は軽量です。 i386では、IDKはなぜその不便な設定を使用するのですか( 'ebx'は呼び出し保存されているので、ほとんどのsyscallラッパーはebxを保存/復元する必要があります) –

+0

@PeterCordesそして関数呼び出し規約は、 'memcpy'に' rep movsb'を実装しています。 – fuz

+0

関数呼び出し規約?多分私はルーキーのように聞こえるでしょう。私はおそらく...だからといって関数呼び出し規約は何ですか?それはアセンブリのことですか? –

答えて

3

x86-64 System V ABIは、最初のAMD64 CPUが販売される前のgccのバージョンでコンパイルされたSPECintの命令数(およびある程度コードサイズ)を最小限に抑えるように設計されています。 this answer for some history and list-archive linksを参照してください。

5分前から、私はすべてのレジスタは同じだと思っていましたが、それは規約のために別々に使用されていました。今すべてのものが私のために変わった

x86-64は完全に直交していません。命令によっては暗黙的に特定のレジスタを使用するものがあります。例えばpushは暗黙的にrspをスタックポインタとして使用し、mul rdirdx:rax = rax*rdiになります。 shl edx, clは、cl(BMI2 shlxまで)のシフトカウントでのみ使用できます。 rep-string命令は、暗黙的にRDI、RSI、およびRCXを使用します。 (そしてrep movs/rep stosは、中大型のmemcpy/memsetとするなど、いくつかのケースで使用して実際に価値がある。)

それは引数渡しレジスタを選択するとのmemcpyへの引数を渡す機能がrep movsとしてそれをインライン化することができるようにことが判明しますJan Hubickaが使用していたメトリックでは有用であったため、最初の2つの引数としてrdirsiが選択されました。しかし、可変回数シフトにはclが必要であるため、rcxは4番目の引数が使用されるまで使用されません。 (そして、ほとんどの機能は、シフト・カウントとしての第三引数を使用して発生しません。)


システムはを呼び出すためにそれがないとしてV ABIは、ほとんどの機能のために同じ呼び出し規約を使用するx86-64のシステム。これは偶然ではない:それはmmapのようなlibcのラッパー関数の実装ができることを意味:

mmap: 
    mov r10, rcx  ; syscall destroys rcx and r11; 4th arg passed in r10 for syscalls 
    mov eax, __NR_mmap 
    syscall 

    cmp rax, -4096 
    ja .set_errno_and_stuff 
    ret 

これは小さな利点であるが、これを行うには理由ないは本当にありません。また、カーネル内のシステムコールのC実装にディスパッチする前に、arg-passingレジスタを設定するカーネル内部のいくつかの命令を保存します。 (システムコール処理のカーネル側を見てみると、this answerを参照してください。主にint 0x80ハンドラについて、私は、私は、64ビットsyscallハンドラを言及し、それがASMから直接、関数のテーブルに派遣していると思います。)

は、関数呼び出しやシステムコールの慣習のためWhat are the calling conventions for UNIX & Linux system calls on i386 and x86-64を参照してください。


i386のシステムコール規則は不格好と不便なものです:ebxは、コール保存するので、ほぼすべてのシステムコールのラッパーがgetpidのような引数なしで呼び出しを除き、ebx保存/復元する必要があります。 (そして、そのためには、カーネルに入る必要さえなくても、単にvDSOを呼び出してください:vDSOやその他のものについては、The Definitive Guide to Linux System Calls (on x86)を参照してください)

しかし、i386関数呼び出し規約では、スタックのため、glibcラッパー関数はまだすべての引数をmovにする必要があります。

x86レジスタの「自然な」順序は、マシンコードの数字コードに従って、また、pusha/popaの順番に従って、EAX、ECX、EDX、EBXです。 Why are first four x86 GPRs named in such unintuitive order?を参照してください。

+0

4番目の引数でユーザランド規約( 'r10'と' rcx')の 'syscall'規約が異なる理由は何ですか?単純なラッパーについては良い点を示していますが、4,5,6の引数を持つ呼び出しの1,2,3引数をシャッフルすることを必要とするこの不一致を除いて、さらに速くなる可能性があります。 – BeeOnRope

+2

@BeeOnRope: 'syscall'命令自体は、保存された' RIP'と 'RFLAGS'値で文字通り' rcx'と 'r11'をクローバーします。これは呼び出し規約の選択において非常にマイナーな要素なので、REXに必要な上位のregsとecxのようなREXのないレジスタのような考慮事項はそれを上回っています。そして、もし規約がarg-passing/call-clobbered "low" regとして 'rcx'の代わりに' rbx'を使用していたならば、可変シフトはそれを安全/復元する必要があります。また、いくつかのコール保存されたローレギュレーション(RBPとRBXは "最小限の特別な"ロー・レジスタ、主にCPUID/CMPXCHG16B(これはもともと存在していなかったため)が必要です。 –

関連する問題