2013-05-07 36 views
5

Tôi đang học để làm ngôn ngữ lắp ráp một lần nữa, và vấn đề duy nhất tôi đã có cho đến nay đã được thực hiện cuộc gọi đến C. Cuốn sách tôi có là hướng đến 32 bit, và tôi đang làm việc trong 64 bit. Rõ ràng có sự khác biệt lớn trong các quy ước gọi điện và trang web http://www.x86-64.org/documentation bị lỗi. Vì vậy, sau khi một số đào/thử nghiệm, biên dịch các chương trình giả trong C và chi tiêu 3 ngày về điều này tôi nghĩ rằng tôi sẽ đăng các phát hiện của tôi nếu nó giúp bất cứ ai khác.Các thông số được chuyển khi gọi Printf từ bit asm 64 bit như thế nào?

RAX có cần được tính số lượng float không? Ngăn xếp chồng "không gian bóng" 16 hoặc 32 bit? Macro này có phù hợp để xếp chồng ngăn xếp cho các chương trình nhỏ không? Tôi biết bạn có thể NOP-pad mã với align, tôi đã không chắc chắn về khung stack.

; 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: Chuỗi đầu tiên. Đây là chuỗi thứ hai ...% s không được diễn giải ở đây. Không phải là% d hoặc% f. Bởi vì nó là một giá trị được truyền. 123 là một số nguyên. Vì vậy, là 456 Floats XMM0: 11.189.196,0000000 XMM1: 1.310700e + 04 XMM2: 0,0011714

Resources: System V ABI v0.96: http://www.uclibc.org/docs/psABI-x86_64.pdf (Nó không phải là có sẵn tại x86-64.org Trang web là xuống) hội Ngôn ngữ Từng bước một. Jeff Duntemann Chương 12 Bộ hướng dẫn 64 bit của Intel. http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

+2

Cách tiếp cận rõ ràng là để viết mã trong C đầu tiên và có một trình biên dịch C tạo ra lắp ráp. Nó sẽ không bao giờ sai. –

Trả lời

6

Có, RAX (thực tế là AL) nên giữ số đăng ký XMM được sử dụng.

Mã liên kết ngăn xếp của bạn quá phức tạp, thông thường bạn chỉ cần thực hiện AND rsp, -16. Ngoài ra, sắp xếp ngăn xếp thường chỉ được thực hiện một lần (thường là lúc bắt đầu main) và sau đó nó được duy trì bằng cách luôn điều chỉnh rsp một cách thích hợp.

SYSV ABI không sử dụng không gian bóng (đó là quy ước microsoft) thay vào đó nó sử dụng "vùng màu đỏ", nhưng điều đó không ảnh hưởng đến trình tự gọi.

Cập nhật về sự liên kết stack:

Trong chức năng mà đã được liên kết RSP (nói chung tất cả mọi thứ trừ main), bạn chỉ cần đảm bảo bất kỳ gọi là chức năng lần lượt được RSP đó là thay đổi bằng một bội số của 16.

Nếu bạn đang sử dụng con trỏ khung chuẩn, thì chức năng của bạn bắt đầu bằng PUSH RBP vì vậy bạn chỉ phải đảm bảo phân bổ không gian theo bội số của 16 (nếu cần), như sau:

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

Nếu không, bạn sẽ phải bồi thường cho 8 byte của RIP đặt trên stack (như bạn một cách chính xác chỉ ra rằng trong bình luận của bạn):

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

Cả hai điều trên chỉ áp dụng nếu bạn gọi các chức năng khác, đó là chức năng lá bạn có thể làm bất cứ điều gì bạn muốn.Bên cạnh đó, vùng đỏ tôi đã đề cập trước đó rất hữu ích trong các chức năng lá, bởi vì bạn có thể sử dụng 128 byte dưới con trỏ ngăn xếp mà không phân bổ rõ ràng, có nghĩa là bạn không cần phải điều chỉnh RSP tại tất cả:

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

Tốt, điều này rất hữu ích. Vì vậy, bất cứ lúc nào tôi đẩy sau khi căn chỉnh ban đầu, làm điều đó như; sub rsp, 10h; mov [rsp], $ value ... sau đó sau khi gọi chỉ cần thêm nó trở lại? – DouglasCodes

+0

Tất cả các cuộc gọi sẽ được căn chỉnh đến 16 trước cuộc gọi phải không? Vì vậy, sau đó cuộc gọi đẩy RIP lên ngăn xếp. Để nó cần phải được điều chỉnh bởi 8 ... vì vậy tôi có thể AND 'rsp, -16' ngay từ đầu và' thêm rsp, 8' trước RET. Chính xác? – DouglasCodes

+0

Cập nhật câu trả lời. – Jester

Các vấn đề liên quan