6

我正在学习再次使用汇编语言,到目前为止我遇到的唯一问题是调用 C。我的书是针对 32 位的,而我正在使用 64 位。显然,调用约定存在很大差异,并且http://www.x86-64.org/documentation站点已关闭。因此,经过一些挖掘/测试,用 C 编译虚拟程序并花费 3 天时间,我想如果它对其他人有帮助,我会发布我的发现。

是否需要为 RAX 提供浮点数?堆栈填充“阴影空间”是 16 位还是 32 位?这个用于对齐堆栈的宏是否可以用于小程序?我知道您可以使用 align 对代码进行 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

输出:第一个字符串。这是第二个字符串...这里不解释 %s。%d 和 %f 都不是。因为它是一个传递的值。123 是一个整数。456 个浮点数也是如此 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 上不可用 站点已关闭)Assembly Language Step By Step。Jeff Duntemann 第 12 章 Intel 64 位指令集。http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

4

1 回答 1

7

是的,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

否则,您将不得不补偿RIP放入堆栈的 8 个字节(正如您在评论中正确指出的那样):

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

上述两种情况仅在您调用其他函数时适用,即在叶函数中您可以做任何您想做的事情。此外,我前面提到的红色区域在叶子函数中很有用,因为您可以使用堆栈指针下的 128 个字节而无需显式分配,这意味着您根本不需要调整RSP

; in leaf functions you can use memory under the stack pointer
; (128 byte red zone)
mov [rsp-8], rax
于 2013-05-07T14:55:31.003 回答