假设我有一个包含许多结构参数的函数(例如Raylib):
void DrawTexturePro(Texture texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint) {
// do something with these
}
完整test.c
:
// Texture, tex data stored in GPU memory (VRAM)
typedef struct Texture {
unsigned int id; // OpenGL texture id
int width; // Texture base width
int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (PixelFormat type)
} Texture;
// Rectangle, 4 components
typedef struct Rectangle {
float x; // Rectangle top-left corner position x
float y; // Rectangle top-left corner position y
float width; // Rectangle width
float height; // Rectangle height
} Rectangle;
// Vector2, 2 components
typedef struct Vector2 {
float x; // Vector x component
float y; // Vector y component
} Vector2;
// Color, 4 components, R8G8B8A8 (32bit)
typedef struct Color {
unsigned char r; // Color red value
unsigned char g; // Color green value
unsigned char b; // Color blue value
unsigned char a; // Color alpha value
} Color;
void DrawTexturePro(Texture texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint) {
// do something with these
}
int main(int argc, char** argv) {
Texture tex = {0, 1, 2, 3, 4};
Rectangle rec = { 0.0f, 0.1f, 0.2f, 0.3f};
Vector2 vec = { 0.4f, 0.5f};
Color color = {'a', 'b', 'c', 'd'};
DrawTexturePro(tex, rec, rec, vec, 0.6f, color);
return 0;
}
当我试图反汇编这段代码时,会看到以下有趣的现象:
_DrawTexturePro: ; @DrawTexturePro
.cfi_startproc
; %bb.0:
sub sp, sp, #64
.cfi_def_cfa_offset 64
ldr w10, [sp, #64]
ldr w9, [sp, #68]
ldr w8, [sp, #72]
str s0, [sp, #48]
str s1, [sp, #52]
str s2, [sp, #56]
str s3, [sp, #60]
str s4, [sp, #32]
str s5, [sp, #36]
str s6, [sp, #40]
str s7, [sp, #44]
str w10, [sp, #24]
str w9, [sp, #28]
str x1, [sp, #8]
ldr w9, [sp, #8]
str w9, [sp, #20]
str w8, [sp, #4]
add sp, sp, #64
ret
.cfi_endproc
完全拆卸:
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 13, 0 sdk_version 13, 1
.globl _DrawTexturePro ; -- Begin function DrawTexturePro
.p2align 2
_DrawTexturePro: ; @DrawTexturePro
.cfi_startproc
; %bb.0:
sub sp, sp, #64
.cfi_def_cfa_offset 64
ldr w10, [sp, #64]
ldr w9, [sp, #68]
ldr w8, [sp, #72]
str s0, [sp, #48]
str s1, [sp, #52]
str s2, [sp, #56]
str s3, [sp, #60]
str s4, [sp, #32]
str s5, [sp, #36]
str s6, [sp, #40]
str s7, [sp, #44]
str w10, [sp, #24]
str w9, [sp, #28]
str x1, [sp, #8]
ldr w9, [sp, #8]
str w9, [sp, #20]
str w8, [sp, #4]
add sp, sp, #64
ret
.cfi_endproc
; -- End function
.globl _main ; -- Begin function main
.p2align 2
_main: ; @main
.cfi_startproc
; %bb.0:
sub sp, sp, #144
stp x29, x30, [sp, #128] ; 16-byte Folded Spill
add x29, sp, #128
.cfi_def_cfa w29, 16
.cfi_offset w30, -8
.cfi_offset w29, -16
mov w8, #0
str w8, [sp, #20] ; 4-byte Folded Spill
stur wzr, [x29, #-4]
stur w0, [x29, #-8]
stur x1, [x29, #-16]
adrp x8, l___const.main.tex@PAGE
add x8, x8, l___const.main.tex@PAGEOFF
ldr q0, [x8]
stur q0, [x29, #-48]
ldr w8, [x8, #16]
stur w8, [x29, #-32]
adrp x8, l___const.main.rec@PAGE
add x8, x8, l___const.main.rec@PAGEOFF
ldr q0, [x8]
str q0, [sp, #64]
adrp x8, l___const.main.vec@PAGE
add x8, x8, l___const.main.vec@PAGEOFF
ldr x8, [x8]
str x8, [sp, #56]
adrp x8, l___const.main.color@PAGE
add x8, x8, l___const.main.color@PAGEOFF
ldr w8, [x8]
str w8, [sp, #52]
ldur q0, [x29, #-48]
add x0, sp, #32
str q0, [sp, #32]
ldur w8, [x29, #-32]
str w8, [sp, #48]
ldr s0, [sp, #64]
ldr s1, [sp, #68]
ldr s2, [sp, #72]
ldr s3, [sp, #76]
ldr s4, [sp, #64]
ldr s5, [sp, #68]
ldr s6, [sp, #72]
ldr s7, [sp, #76]
ldr w10, [sp, #56]
ldr w9, [sp, #60]
ldr w8, [sp, #52]
str w8, [sp, #24]
ldr x1, [sp, #24]
mov x8, sp
str w10, [x8]
str w9, [x8, #4]
mov w9, #39322
movk w9, #16153, lsl #16
fmov s16, w9
str s16, [x8, #8]
bl _DrawTexturePro
ldr w0, [sp, #20] ; 4-byte Folded Reload
ldp x29, x30, [sp, #128] ; 16-byte Folded Reload
add sp, sp, #144
ret
.cfi_endproc
; -- End function
.section __TEXT,__const
.p2align 2 ; @__const.main.tex
l___const.main.tex:
.long 0 ; 0x0
.long 1 ; 0x1
.long 2 ; 0x2
.long 3 ; 0x3
.long 4 ; 0x4
.section __TEXT,__literal16,16byte_literals
.p2align 2 ; @__const.main.rec
l___const.main.rec:
.long 0x00000000 ; float 0
.long 0x3dcccccd ; float 0.100000001
.long 0x3e4ccccd ; float 0.200000003
.long 0x3e99999a ; float 0.300000012
.section __TEXT,__literal8,8byte_literals
.p2align 2 ; @__const.main.vec
l___const.main.vec:
.long 0x3ecccccd ; float 0.400000006
.long 0x3f000000 ; float 0.5
.section __TEXT,__literal4,4byte_literals
l___const.main.color: ; @__const.main.color
.byte 97 ; 0x61
.byte 98 ; 0x62
.byte 99 ; 0x63
.byte 100 ; 0x64
似乎传递了参数,以便 * 结构的部分位于多个寄存器中 *。根据AArch 64参数传递规则,如果复合类型(在本例中为结构?)大于16字节,则规则B.4
指示将其复制到已分配内存并作为地址传递。
如果参数类型是大于16字节的复合类型,则将参数复制到调用方分配的内存中,并将参数替换为指向副本的指针。
但是,Rectangle
是一个由4个浮点值组成的结构体,因此其大小至少为32字节。那么为什么将其成员传递给s0-s3
和s4-s7
(我的反汇编代码的第71到79行)而不仅仅是在寄存器中传递的单个地址(顺便问一下,如果是这种情况,该地址将用于哪个寄存器组,常规寄存器还是浮点寄存器?)
Rectangle
的大小只有16字节,因为每个IEEE-754浮点数是4字节。编译器是正确的。(感谢@Siguza)
我有两个问题:
1.如果我查看C函数声明,我如何知道编译器希望我使用AArch 64汇编向它传递参数的方式?(例如,在一个寄存器上传递结构体的地址与在多个寄存器上传递结构体的值)
1.AArch 64过程调用标准是否以某种方式解决了它,而我只是没有看到它,或者这真的没有定义?
编辑:在评论中@httpdigest的指针之后澄清了问题。
EDIT 2:@Siguza评论后修复了问题错误。
1条答案
按热度按时间snz8szmq1#
感谢@httpdigest和@Siguza,我想我的问题的答案如下:
aarch 64的参数传递规则可以在这里找到。与标准不同的达尔文规则可以在here中找到。
要确定在查看函数时传递参数的正确方式:
1.了解参数的大小。检查参数是否大于16字节。如果大于,则分配内存,将其复制到所述内存中,并传递一个指针到第一个可用的通用寄存器。
1.如果param小于16个字节,并且不是复合类型,则根据机器类型(参考此处)将其传递到通用寄存器(例如x 0-x7)或浮点寄存器(例如q 0-q7)。
1.如果param是一个小于16字节的结构体,那么它的每个元素都将被逐个加载到寄存器中(例如,我的反汇编中的第70-73行显示了
Rectangle
如何作为s 0到s3上的四个浮点数传递)。非常感谢大家!这对我来说现在更有意义了。