Dou*_*des 6 assembly printf x86-64 abi calling-convention
我正在学习再次使用汇编语言,到目前为止我遇到的唯一问题就是调用C语言.我所拥有的书是32位,而我的工作是64位.显然,调用约定存在很大差异,并且http://www.x86-64.org/documentation站点已关闭.因此,经过一些挖掘/测试,在C中编译虚拟程序并花费3天时间,我想我会发布我的发现,如果它可以帮助其他人.
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, 0123 ; 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
Run Code Online (Sandbox Code Playgroud)
输出:第一个字符串.这是第二个字符串......%s不在这里解释.既不是%d也不是%f.因为它是一个传递的值.123是整数.456 Floats XMM0:11189196.0000000 XMM1:1.310700e + 04 XMM2:0.0011714
资源:System V ABI v0.96:http://www.uclibc.org/docs/psABI-x86_64.pdf (x86-64.org网站已关闭)汇编语言一步一步.Jeff Duntemann第12章Intel 64位指令集.http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
是的,RAX
(实际上AL
)应该保留使用的XMM
寄存器数量.
您的堆栈对齐代码过于复杂,通常您只是这样做AND rsp, -16
.此外,堆栈对齐通常只进行一次(通常在开始时main
),然后通过始终rsp
适当调整来维持堆栈对齐.
SYSV ABI不使用阴影空间(即微软约定),而是使用"红色区域",但这不会影响调用序列.
有关堆栈对齐的更新:
在已经对齐的函数中RSP
(通常是除了之外的main
所有函数),您只需确保任何被调用的函数依次将RSP
其更改为16的倍数.
如果您使用标准帧指针,那么您的函数以a开头,PUSH RBP
那么您只需要确保以16的倍数(如果需要)分配空间,如下所示:
push rbp
mov rbp, rsp
sub rsp, n*16
...
mov rsp, rbp
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
否则,你将不得不补偿RIP
堆栈中8个字节的放置(正如你在评论中正确指出的那样):
sub rsp, n*16+8
...
add rsp, n*16+8
ret
Run Code Online (Sandbox Code Playgroud)
上述两种方法仅适用于您调用其他函数,即在叶函数中,您可以执行任何操作.另外,我前面提到的红色区域在叶子函数中很有用,因为你可以在堆栈指针下使用128个字节而不需要显式分配,这意味着你根本不需要调整RSP
:
; in leaf functions you can use memory under the stack pointer
; (128 byte red zone)
mov [rsp-8], rax
Run Code Online (Sandbox Code Playgroud)