如何在从arm程序集调用c函数时传递长类型参数?

时间:2022-06-26 03:10:36

I have a C function witch looks like:

我有一个C函数,看起来像:

int foo(int a, long long b);

I'm trying to call it from arm assembly, but I don't know how to deal with the second parameter(long long).

我试图从arm汇编中调用它,但是我不知道如何处理第二个参数(长)。

3 个解决方案

#1


3  

The ARM EABI/AAPCS specifies that 64bit types should be passed in 2 registers which are next to each other and the first register must be even numbered. In little endian mode the high part resides in the higher numbered register, while the low part is put in the lowered numbered one. In big endian mode it's vice versa.

ARM EABI/AAPCS规定64位类型应该在相邻的两个寄存器中传递,并且第一个寄存器必须被偶数编号。在小恩德式中,高的部分位于高的编号寄存器中,而低的部分放在低的编号寄存器中。在大端模式下,反之亦然。

Both requirements are there to accomodate the strd/ldrd instructions, which can save two registers in a single instructions.

这两个要求都适用于strd/ldrd指令,它可以在一个指令中保存两个寄存器。

So, to pass 0x0123456789abcdef for your example in little endian mode you have to load the registers in the following way:

因此,为了在little endian模式下通过0x0123456789abcdef,您必须按照以下方式加载寄存器:

mov r0, a
// R1 is unused
ldr r2, =0x89abcdef
ldr r3, =0x01234567

#2


0  

(Beware: wrong answer; cannot delete it because the comments contain info)

(注意:错误的答案;无法删除,因为注释包含信息)

According to the ARM ABI, the second parameter is passed in registers r1 and r2. If your machine is little-endian, pass the low part in r1 and the high one in r2 (i don't know if this is opposite for big-endian machines). So to call the function with a parameter e.g. 0x123456789abcd:

根据ARM ABI,第二个参数在寄存器r1和r2中传递。如果您的机器是little-endian,则传递r1中的low部分和r2中的high部分(我不知道这是否与big-endian机器相反)。用参数调用函数,例如0x123456789abcd:

MOV r0, ... (the value of "a")
MOV r1, #0x6789abcd
MOV r2, #0x12345
... (call the function)

#3


0  

Just ask the compiler it will tell you everything...

只要问编译器它会告诉你一切……

int foo ( int a, long long b );

int bar  ( void )
{
    return(foo(0xAABB,0x1122334455667788LL));
}

I prefer to compile then disassemble rather than compile to asm, easier to read.

我更喜欢编译然后分解,而不是编译到asm,这样更容易阅读。

arm-none-eabi-gcc -c -O2 fun.c -o fun.o
arm-none-eabi-objdump -D fun.o

fun.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <bar>:
   0:   e92d4008    push    {r3, lr}
   4:   e59f001c    ldr r0, [pc, #28]   ; 28 <bar+0x28>
   8:   e28f3010    add r3, pc, #16
   c:   e893000c    ldm r3, {r2, r3}
  10:   ebfffffe    bl  0 <foo>
  14:   e8bd4008    pop {r3, lr}
  18:   e12fff1e    bx  lr
  1c:   e1a00000    nop         ; (mov r0, r0)
  20:   55667788    strbpl  r7, [r6, #-1928]!   ; 0x788
  24:   11223344    teqne   r2, r4, asr #6
  28:   0000aabb            ; <UNDEFINED> instruction: 0x0000aabb
  2c:   e1a00000    nop         ; (mov r0, r0)

and the answer is r0 contains the first parameter, r1 skipped and r2/r3 contain the long long.

答案是r0包含第一个参数,r1跳过,r2/r3包含长。

#1


3  

The ARM EABI/AAPCS specifies that 64bit types should be passed in 2 registers which are next to each other and the first register must be even numbered. In little endian mode the high part resides in the higher numbered register, while the low part is put in the lowered numbered one. In big endian mode it's vice versa.

ARM EABI/AAPCS规定64位类型应该在相邻的两个寄存器中传递,并且第一个寄存器必须被偶数编号。在小恩德式中,高的部分位于高的编号寄存器中,而低的部分放在低的编号寄存器中。在大端模式下,反之亦然。

Both requirements are there to accomodate the strd/ldrd instructions, which can save two registers in a single instructions.

这两个要求都适用于strd/ldrd指令,它可以在一个指令中保存两个寄存器。

So, to pass 0x0123456789abcdef for your example in little endian mode you have to load the registers in the following way:

因此,为了在little endian模式下通过0x0123456789abcdef,您必须按照以下方式加载寄存器:

mov r0, a
// R1 is unused
ldr r2, =0x89abcdef
ldr r3, =0x01234567

#2


0  

(Beware: wrong answer; cannot delete it because the comments contain info)

(注意:错误的答案;无法删除,因为注释包含信息)

According to the ARM ABI, the second parameter is passed in registers r1 and r2. If your machine is little-endian, pass the low part in r1 and the high one in r2 (i don't know if this is opposite for big-endian machines). So to call the function with a parameter e.g. 0x123456789abcd:

根据ARM ABI,第二个参数在寄存器r1和r2中传递。如果您的机器是little-endian,则传递r1中的low部分和r2中的high部分(我不知道这是否与big-endian机器相反)。用参数调用函数,例如0x123456789abcd:

MOV r0, ... (the value of "a")
MOV r1, #0x6789abcd
MOV r2, #0x12345
... (call the function)

#3


0  

Just ask the compiler it will tell you everything...

只要问编译器它会告诉你一切……

int foo ( int a, long long b );

int bar  ( void )
{
    return(foo(0xAABB,0x1122334455667788LL));
}

I prefer to compile then disassemble rather than compile to asm, easier to read.

我更喜欢编译然后分解,而不是编译到asm,这样更容易阅读。

arm-none-eabi-gcc -c -O2 fun.c -o fun.o
arm-none-eabi-objdump -D fun.o

fun.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <bar>:
   0:   e92d4008    push    {r3, lr}
   4:   e59f001c    ldr r0, [pc, #28]   ; 28 <bar+0x28>
   8:   e28f3010    add r3, pc, #16
   c:   e893000c    ldm r3, {r2, r3}
  10:   ebfffffe    bl  0 <foo>
  14:   e8bd4008    pop {r3, lr}
  18:   e12fff1e    bx  lr
  1c:   e1a00000    nop         ; (mov r0, r0)
  20:   55667788    strbpl  r7, [r6, #-1928]!   ; 0x788
  24:   11223344    teqne   r2, r4, asr #6
  28:   0000aabb            ; <UNDEFINED> instruction: 0x0000aabb
  2c:   e1a00000    nop         ; (mov r0, r0)

and the answer is r0 contains the first parameter, r1 skipped and r2/r3 contain the long long.

答案是r0包含第一个参数,r1跳过,r2/r3包含长。