2013-05-07 3 views
5

어셈블리 언어를 다시 배우는 중입니다. 지금까지 가지고있는 유일한 문제는 C에 대한 호출이었습니다. 제가 가지고있는 책은 32 비트에 맞추어졌고 64 비트로 작업하고 있습니다. 명백하게 호출 규칙에 큰 차이가 있으며 http://www.x86-64.org/documentation 사이트가 다운되었습니다. 그래서 일부 파기/테스트 후, C로 더미 프로그램을 컴파일하고 3 일을 보냈다. 다른 사람들에게 도움이된다면 내 결과를 게시 할 것이라고 생각했다.64 비트 ASM에서 Printf를 호출 할 때 params는 어떻게 전달됩니까?

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 : 첫 번째 문자열. 이것은 두 번째 문자열입니다 ... % 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입니다 단계별. 제프 Duntemann 12 장 인텔 64 비트 명령어 세트. http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

+2

명백한 접근 방식을 : 당신이 모든 RSP을 조정하지 않아도을 의미 명시 적으로 할당하지 않고 스택 포인터 아래에 128 바이트를 사용할 수 있기 때문에 또한, 앞서 언급 빨간색 영역, 잎 기능에 유용하다 먼저 C로 코드를 작성하고 C 컴파일러에서 어셈블리를 생성하도록하십시오. 결코 틀린 일은 아닙니다. –

답변

6

예, RAX (실제로는 AL)은 사용 된 XMM 레지스터의 번호를 보유해야합니다.

스택 정렬 코드가 복잡합니다. 보통 AND rsp, -16입니다. 또한 스택 정렬은 일반적으로 한 번만 수행되고 (보통 main 시작) 항상 rsp을 적절하게 조정하여 유지합니다.

SYSV ABI는 "빨간 영역"을 사용하는 대신 음영 공간 (마이크로 소프트 규칙)을 사용하지 않지만 호출 순서에는 영향을 미치지 않습니다. 스택 정렬에 대한

업데이트 : 이미 RSP (main를 제외하고 일반적으로 모든 것을) 정렬되는 함수에서

, 당신은 단지 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 

위의 모두 당신이 호출하는 경우에만 적용 리프 함수에있는 다른 함수는 원하는대로 할 수 있습니다.

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

니스, 매우 도움이됩니다. 따라서 초기 정렬 이후에 언제든지 밀어 넣으십시오. sub rsp, 10h; mov [rsp], $ value ... 호출 후 그냥 다시 추가 하시겠습니까? – DouglasCodes

+0

모든 통화가 통화 전에 16으로 정렬됩니까? 그러면 호출은 RIP를 스택으로 푸시합니다. 8로 조정할 필요가있는 채로 남겨두면 ... 처음에는'rsp, -16 '을, RET 전에'add rsp, 8 '을 할 수 있습니다. 옳은? – DouglasCodes

+0

답변이 업데이트되었습니다. – Jester

관련 문제