2013-05-07 18 views
5

私はアセンブリ言語をやり直すことを学んでいます。これまで私が持っていた唯一の問題はCへの呼び出しでした。私の持っている本は32ビットに合わせてあり、私は64ビットで作業しています。明らかに呼び出し規約に大きな違いがあり、http://www.x86-64.org/documentationサイトがダウンしています。だから、いくつかの掘削/テストの後、Cでダミーのプログラムをコンパイルし、これに3日間費やしてみたら、誰かを助けるなら私の所見を投稿するだろうと思った。64ビットのasmからPrintfを呼び出すときに、どのようにパラメータが渡されますか?

RAXに浮動小数点数を指定する必要がありますか? スタックパディング "シャドースペース"は16ビットか32ビットですか? このマクロは、小さなプログラムのスタックを通過させるためのものですか?私はあなたがNOPパッドでコードを整列させることができることを知っています、私はスタックフレームについてはわかりませんでした。

; pf.asm compiled with 'nasm -o pf.o -f elf64 -g -F stabs' 
; linked with 'gcc -o pf pf.o' 
; 64-bit Bodhi (ubuntu) linux 

%include "amd64_abi.mac" 
[SECTION .data] 
First_string: db "First string.",10,"%s", "%d is an integer. So is %d",10 
       db "Floats XMM0:%5.7f XMM1:%.6le XMM2:%lg",10,0 
Second_String: db "This is the second string... %s's are not interpreted here.",10 
       db " Neither are %d's nor %f's. 'Cause it is a passed value.", 10, 0 
; Just a regular string for insert. 
[SECTION .bss] 
[SECTION .text] 
EXTERN printf 
GLOBAL main 
main: 
_preserve_64AMD_ABI_regs ; Saves RBP, RBX, R12-R15 
mov rdi, First_string ; Start of string to be formatted. Null terminated 
mov rsi, Second_String ; String addy of first %s in main string. Not interpretted 
mov rcx, 0456   ; Second Integer (Register is specific for ordered arguments.) 
mov rdx,; First integer (Order of assignment does not matter.) 
         ; Order of Integer/Pointer Registers: 
         ; $1:RDI $2:RSI $3:RDX $4:RCX $5:R8 $6:R9 

mov rax,0AABBCCh   ; Test value to be stored in xmm0 
cvtsi2sd xmm0, rax  ; Convert quad to scalar double 
mov rax,003333h   ; Test value to be stored in xmm1 
cvtsi2sd xmm1, rax  ; Convert quad to scalar double 
cvtsi2sd xmm2, rax  ; Convert quad to scalar double 
divsd xmm2, xmm0  ; Divide scalar double 

sub rsp, 16    ; Allocates 16 byte shadow memory 
_prealign_stack_to16 ; Move to the lower end 16byte boundry (Seg-Fault otherwise) 
; mov rax, 3    ; Count of xmm registers used for floats. ?!needed?! 
Before_Call: 
call printf    ; Send the formatted string to C-printf 
_return_aligned_stack ; Returns RSP to the previous alignment 
add rsp, 16    ; reallocate shadow memory 

_restore_64AMD_ABI_regs_RET 
; Ends pf.asm 

; amd64_abi.mac 
; Aligns stack (RSP) to 16 byte boundry, padding needed amount in rbx 
%macro _preserve_64AMD_ABI_regs 0 
push rbp 
mov rbp, rsp 
push rbx 
push r12 
push r13 
push r14 
push r15 
%endmacro 

%macro _restore_64AMD_ABI_regs_RET 0 
pop r15 
pop r14 
pop r13 
pop r12 
pop rbx 
mov rsp, rbp 
pop rbp 
ret 
%endmacro 

%macro _prealign_stack_to16 0 
mov rbx, 0Fh   ; Bit mask for low 4-bits 10000b = 16 :: 01111b = 15b 
and rbx, rsp   ; get bits 0-3 into rbx 
sub rsp, rbx   ; remove them from rsp, rounding down to multiple of 16 (10h) 
%endmacro 

; De-aligns stack (RSP)from 16 byte boundry using saved rbx offset 
%macro _return_aligned_stack 0 
add rsp, rbx 
%endmacro 

OUTPUT: 最初の文字列。 これは2番目の文字列です。%sはここで解釈されません。 %dでも%fでもありません。それは渡された値なので。 123は整数です。 11189196.0000000 XMM1:1.310700e + 04 XMM2:0.0011714

資源: システムV ABIのv0.96:http://www.uclibc.org/docs/psABI-x86_64.pdf(それはx86-64.orgサイトでは利用できませんがダウンしている) アセンブリ言語だから、456 フロートXMM0ですステップバイステップ。 Jeff Duntemann Chapter 12 Intel 64ビット命令セット。 http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

+2

明白なアプローチ最初にC言語でコードを記述し、Cコンパイラにアセンブリを生成させることです。それは決して悪いことではありません。 –

答えて

6

はい、RAX(実際にはAL)は、使用されるXMMレジスタの数を保持する必要があります。

スタックアライメントコードが複雑すぎます。通常はAND rsp, -16となります。また、スタックアライメントは通常1回だけ(通常mainの開始時に)実行され、その後は常にrspを適切に調整することによって維持されます。

SYSV ABIは "赤いゾーン"を使用する代わりに、シャドウ領域を使用しません(これはMicrosoftの規則です)が、呼び出しシーケンスには影響しません。スタックのアライメントについて

更新:すでにRSPmain除いて、一般的に、すべてを)整列取得機能で

、あなただけ必ず順番に呼び出された関数が16

の倍数で変化しています RSPをプレゼント

標準のフレームポインタを使用している場合は、関数はPUSH RBPで始まりますので、必要に応じて16の倍数でスペースを割り当てるようにしてください。

push rbp 
mov rbp, rsp 
sub rsp, n*16 
... 
mov rsp, rbp 
pop rbp 
ret 

そうでない場合は、あなたがスタック上RIPプットの8つのバイトを補償する必要があります(あなたが正しくあなたのコメントでそれを指摘したように):

sub rsp, n*16+8 
... 
add rsp, n*16+8 
ret 

上記のいずれもが、あなたが呼び出す場合にのみ適用されます他の関数、つまりリーフ関数では、必要なものを何でもできます。また、あなたがすべてでRSPを調整する必要はありません。つまり、明示的に割り当てずに、スタックポインタの下に128バイトを使用することができますので、私は先に述べたレッドゾーンは、リーフ関数で有用です:

; in leaf functions you can use memory under the stack pointer 
; (128 byte red zone) 
mov [rsp-8], rax 
+0

ニース、これは非常に役に立ちます。だから私は最初のアライメントの後にプッシュするたびに、サブrsp、10h; mov [rsp]、$ value ...呼び出した後にそれを追加するだけですか? – DouglasCodes

+0

すべての通話は、通話の権利の前に16に調整されますか?コールはRIPをスタックにプッシュします。 8で調整する必要があるので、始めに 'rsp、-16'、RETの前に' add rsp、8'を書くことができます。正しい? – DouglasCodes

+0

答えを更新しました。 – Jester

関連する問題