2013-05-07 12 views
5

Uczę się znowu języka asemblerowego, a jedyny problem, jaki miałem do tej pory, to nawiązywanie połączeń z C. Książka, którą mam, jest przystosowana do 32-bitowego, a ja pracuję w 64-bitowym. Najwyraźniej istnieje duża różnica w konwencjach wywoływania, a witryna http://www.x86-64.org/documentation jest niedostępna. Więc po kilku kopaniu/testowaniu, kompilowaniu programów dummy w C i spędzeniu 3 dni na tym pomyślałem, że opublikuję moje wyniki, jeśli pomoże to ktokolwiek inny.W jaki sposób przekazywane są parametry podczas wywoływania Printf z 64-bitowego asm?

Czy RAX wymaga podania liczby zmiennoprzecinkowej? Czy wyściółka stosu "przestrzeń cienia" 16 lub 32 bity? Czy to makro służy do dopasowywania stosu do potrzeb użytkownika w przypadku małych programów? Wiem, że możesz NOP-pad kod z wyrównaniem, nie byłem pewien ramie stosu.

; 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 

WYJŚCIE: Pierwszy ciąg. To jest drugi ciąg ...% s nie są tutaj interpretowane. Nie ma również% d, ani% f. Ponieważ jest to przekazana wartość. 123 jest liczbą całkowitą. Więc jest 456 pływaków XMM0: +11189196,0000000 XMM1: 1.310700e + 04 XMM2: 0,0011714

Zasoby: System V ABI v0.96: http://www.uclibc.org/docs/psABI-x86_64.pdf (nie jest dostępny w x86-64.org Witryna jest w trakcie) Zgromadzenie Język Krok po kroku. Jeff Duntemann Rozdział 12 Zestaw instrukcji Intel 64-bit. http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

+2

oczywistym podejściem jest napisanie kodu w C najpierw i mieć kompilator C generuje złożenie. To nigdy nie będzie złe. –

Odpowiedz

6

Tak, RAX (faktycznie AL) powinien zawierać liczbę użytych rejestrów XMM.

Twój kod wyrównania stosu jest zbyt skomplikowany, zwykle po prostu robisz AND rsp, -16. Ponadto wyrównanie stosu jest zwykle wykonywane tylko raz (zwykle na początku main), a następnie jest utrzymywane przez odpowiednie dostosowanie wartości rsp.

SYSV ABI nie korzysta z przestrzeni cienia (to konwencja microsoft) zamiast tego używa "czerwonej strefy", ale to nie ma wpływu na sekwencję wywołującą.

Aktualizacja o wyrównanie stosu:

W funkcjach, które już się wyrównane RSP (ogólnie wszystko oprócz main), po prostu upewnij się jakieś zwane funkcje z kolei uzyskać RSP się zmieniło przez wielokrotność 16.

Jeśli używasz standardowego wskaźnika ramki, twoje funkcje zaczynają się od PUSH RBP, więc musisz tylko upewnić się, że alokujesz spację w wielokrotności 16 (jeśli jest to konieczne), tak jak:

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

W przeciwnym razie będziesz musiał zrekompensować 8 bajtów RIP umieszczone na stosie (jak słusznie zauważył, że w swoim komentarzu):

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

Oba powyższe stosuje się tylko jeśli zadzwonisz inne funkcje, czyli funkcje liścia, możesz robić, co chcesz.Ponadto, czerwona strefa wspominałem wcześniej jest przydatna w funkcji liści, ponieważ można używać 128 bajtów na podstawie wskaźnika stosu bez wyraźnego podziału, co oznacza, nie trzeba regulować RSP w ogóle:

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

Fajnie, to bardzo pomocne. Tak więc w dowolnym momencie naciskając po początkowym wyrównaniu, wykonaj to jako; subspsp, 10h; mov [rsp], $ value ... następnie po połączeniu dodaj ją ponownie? – DouglasCodes

+0

Wszystkie połączenia zostaną wyrównane do 16 przed właściwym połączeniem? Tak więc połączenie popycha RIP na stos. Pozostawiając to wymagające korekty o 8 ... abym mógł ICH 'rsp, -16' na początku i' dodać rsp, 8' przed RET. Poprawny? – DouglasCodes

+0

Zaktualizowano odpowiedź. – Jester

Powiązane problemy