Arm汇编 - 调用超过4个参数的函数

9

我知道在汇编中调用函数时,r0至r3包含第一个参数至第四个参数。当参数超过四个时,栈指针会被使用,但是我不太确定具体情况。r0-r3是否仍然保留第一个四个参数,其余的放在堆栈上?我正在查看下面的汇编代码,试图理解它是如何调用mach_msg(一个有七个参数的函数)。进入这段代码时,r0和r1包含两个参数。

var_38          = -0x38
var_34          = -0x34
var_30          = -0x30
var_2C          = -0x2C
var_24          = -0x24
var_20          = -0x20
var_18          = -0x18
var_14          = -0x14
var_10          = -0x10
var_C           = -0xC
00001220
00001220                 PUSH            {R7,LR}
00001222                 MOV             R7, SP
00001224                 SUB             SP, SP, #0x30
00001226                 MOV             R2, (_NDR_record_ptr - 0x1232) ; _NDR_record_ptr
0000122E                 ADD             R2, PC ; _NDR_record_ptr
00001230                 LDR             R2, [R2] ; _NDR_record
00001232                 LDR             R3, [R2]
00001234                 LDR             R2, [R2,#4]
00001236                 STR             R2, [SP,#0x38+var_10]
00001238                 MOVS            R2, #0x24 ; '$'
0000123A                 STR             R3, [SP,#0x38+var_14]
0000123C                 MOVS            R3, #0
0000123E                 STRB.W          R1, [SP,#0x38+var_C]
00001242                 MOVS            R1, #0x13
00001244                 STR             R1, [SP,#0x38+var_2C]
00001246                 MOVS            R1, #1
00001248                 STR             R0, [SP,#0x38+var_24]
0000124A                 MOV             R0, 0x1E84EA
00001252                 STR             R3, [SP,#0x38+var_20]
00001254                 STR             R3, [SP,#0x38+var_38]
00001256                 STR             R3, [SP,#0x38+var_34]
00001258                 STR             R0, [SP,#0x38+var_18]
0000125A                 STR             R3, [SP,#0x38+var_30]
0000125C                 ADD             R0, SP, #0x38+var_2C
0000125E                 BLX             _mach_msg
00001262                 ADD             SP, SP, #0x30
00001264                 POP             {R7,PC}

以下是所谓的东西的定义和用法:

标签定义段落。

typedef struct {
    unsigned char       mig_vers;
    unsigned char       if_vers;
    unsigned char       reserved1;
    unsigned char       mig_encoding;
    unsigned char       int_rep;
    unsigned char       char_rep;
    unsigned char       float_rep;
    unsigned char       reserved2;
} NDR_record_t;
extern NDR_record_t NDR_record;
extern mach_msg_return_t    mach_msg(
                mach_msg_header_t *msg,
                mach_msg_option_t option,
                mach_msg_size_t send_size,
                mach_msg_size_t rcv_size,
                mach_port_name_t rcv_name,
                mach_msg_timeout_t timeout,
                mach_port_name_t notify);

据我的理解,堆栈指针会向后移动48个字节用于存储变量。这48个字节是为了存储额外的三个参数还是所有参数都需要使用这48个字节呢?
3个回答

6

在这48个字节中,12个字节用于额外的三个参数,其余的用于本地变量。您可以在代码中看到这一点,该函数通过r0到r3传递了四个参数,另一个参数在[SP,#0x38 + var_38](如果您进行计算将解析为[sp]),另一个在[sp,#4],最后一个在[sp,#8]。


那么剩余的参数是从堆栈指针的开头开始吗? - user1000039
没错,[sp] 就是这个意思。 - Raymond Chen

1
unsigned int fun
(
    unsigned int a,
    unsigned int b,
    unsigned int c,
    unsigned int d,
    unsigned int e,
    unsigned int f
)
{
    a+=1;
    a|=b+2;
    a&=c+4;
    a^=d+5;
    a-=e+6;
    a|=~f;
    return(a);
}


00000000 <fun>:
   0:   e2800001    add r0, r0, #1
   4:   e2811002    add r1, r1, #2
   8:   e181c000    orr ip, r1, r0
   c:   e2822004    add r2, r2, #4
  10:   e002100c    and r1, r2, ip
  14:   e59d0000    ldr r0, [sp]
  18:   e2833005    add r3, r3, #5
  1c:   e023c001    eor ip, r3, r1
  20:   e59d1004    ldr r1, [sp, #4]
  24:   e060200c    rsb r2, r0, ip
  28:   e2420006    sub r0, r2, #6
  2c:   e1e03001    mvn r3, r1
  30:   e1800003    orr r0, r0, r3
  34:   e12fff1e    bx  lr

前四个寄存器依次为r0 = a,r1 = b,r2 = c,r3 = d,然后其余的按相反顺序推入,以便sp + 0是e,sp + 4是f。

如果您有一个64位整数,则需要两个寄存器,因此您可以使用r0-r3来存储四个int或两个int和一个long long,或两个long long等。


0

我记得,尽可能多的寄存器(r0-r3或4个字)可以通过寄存器传递。其余的则通过堆栈传递。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接