assembly 如何确定在arm64汇编中传递结构体参数的正确方式?

1sbrub3j  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(156)

假设我有一个包含许多结构参数的函数(例如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-s3s4-s7(我的反汇编代码的第71到79行)而不仅仅是在寄存器中传递的单个地址(顺便问一下,如果是这种情况,该地址将用于哪个寄存器组,常规寄存器还是浮点寄存器?)

Rectangle的大小只有16字节,因为每个IEEE-754浮点数是4字节。编译器是正确的。(感谢@Siguza)
我有两个问题:
1.如果我查看C函数声明,我如何知道编译器希望我使用AArch 64汇编向它传递参数的方式?(例如,在一个寄存器上传递结构体的地址与在多个寄存器上传递结构体的值)
1.AArch 64过程调用标准是否以某种方式解决了它,而我只是没有看到它,或者这真的没有定义?
编辑:在评论中@httpdigest的指针之后澄清了问题。
EDIT 2:@Siguza评论后修复了问题错误。

snz8szmq

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上的四个浮点数传递)。
非常感谢大家!这对我来说现在更有意义了。

相关问题