如何定义可在C语言中使用的ARM汇编函数

时间:2019-04-04 14:28:41

标签: assembly arm gnu-toolchain

我已经学习C几个月了,现在我开始更深入地研究低级语言-ARM汇编,因此,我决定从一个非常基本的项目开始,制作一个汇编文件.S。定义阶乘函数,然后在C中调用它并使用它。因此,我想问一下汇编程序是否可以用于定义这种复杂函数,并且可以用作C中的另一个函数?如果您不介意,请给我一个.S文件的简单示例,其中一个函数将2个数字从标准输入num1和num2加载到寄存器中,计算num1 * num2并返回定义的结果,并且可以在C源代码中使用文件?

感谢您的阅读。如果这个问题很愚蠢,至少请给我一个方向,以便我可以自己跟踪并找出来。

2 个答案:

答案 0 :(得分:0)

要使用用C用汇编语言编写的函数,您主要需要做的事情:

  1. 声明但不使用C定义函数。
  2. 坚持ARM调用约定。

声明

声明起来很容易,例如:

int add(int a, int b);

这是一个声明,因为它不包含函数的主体。当然,名称(在这种情况下为 add )必须匹配。

如果在C ++中使用它,则必须添加extern "C"

extern "C" int add(int a, int b);

通话约定

调用约定定义如何将参数传递给函数以及从函数返回参数,以及必须保存哪些寄存器。您需要熟悉这些细节。可以在ARM (A32) calling convention上找到简化的概述。

一个超短而且非常简化的版本是:

  • 前四个参数在R0中传递给R3,其余四个参数在堆栈中传递。
  • 返回值在R0中返回。
  • 必须保存和还原R0至R3以外的寄存器。

上述功能的简单实现是:

add:
        add     r0, r0, r1
        bx      lr

a在R0中传递,b在R1中传递。结果在R0中返回。 R3以上的寄存器不会被保存,因为它们未被触摸。

更广泛的版本如下:

add:
        str     fp, [sp, #-4]!
        add     fp, sp, #0
        sub     sp, sp, #12
        str     r0, [fp, #-8]
        str     r1, [fp, #-12]
        ldr     r2, [fp, #-8]
        ldr     r3, [fp, #-12]
        add     r3, r2, r3
        mov     r0, r3
        add     sp, fp, #0
        ldr     fp, [sp], #4
        bx      lr

这基本上是 add 函数的 debug 版本:在堆栈上分配了空间,用于存储ab作为局部变量,帧指针寄存器(fp)指向局部变量。最后,一切都将恢复。

答案 1 :(得分:0)

大多数理智的编译器都会编译为汇编,然后调用汇编器将其转换为对象。

unsigned int fun ( unsigned int a, unsigned int b)
{
    return((a<<1)+(b^0xFF));
}

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

00000000 <fun>:
   0:   e22110ff    eor r1, r1, #255    ; 0xff
   4:   e0810080    add r0, r1, r0, lsl #1
   8:   e12fff1e    bx  lr

即使允许组装输出,我仍然认为这是读取输出的最简单方法。

但是你可以做到

arm-none-eabi-gcc -O2 -S so.c -o so.s

arm-none-eabi-gcc -O2 -c -save-temps so.c -o so.o

然后看

     cat so.s
    .cpu arm7tdmi
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 1
    .eabi_attribute 30, 2
    .eabi_attribute 34, 0
    .eabi_attribute 18, 4
    .file   "so.c"
    .text
    .align  2
    .global fun
    .arch armv4t
    .syntax unified
    .arm
    .fpu softvfp
    .type   fun, %function
fun:
    @ Function supports interworking.
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    @ link register save eliminated.
    eor r1, r1, #255
    add r0, r1, r0, lsl #1
    bx  lr
    .size   fun, .-fun
    .ident  "GCC: (GNU) 8.2.0"

您可以自己组装的

arm-none-eabi-as so.s -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <fun>:
   0:   e22110ff    eor r1, r1, #255    ; 0xff
   4:   e0810080    add r0, r1, r0, lsl #1
   8:   e12fff1e    bx  lr

并获得相同的对象,就像您没有单独执行步骤一样。这也意味着您可以只用汇编语言编写自己的函数,然后将其链接到项目中,就像使用C编译对象一样。

    .global fun
fun:
    eor r1, r1, #255
    add r0, r1, r0, lsl #1
    bx  lr

arm-none-eabi-as so.s -o so.o
arm-none-eabi-objdump -D so.o

Disassembly of section .text:

00000000 <fun>:
   0:   e22110ff    eor r1, r1, #255    ; 0xff
   4:   e0810080    add r0, r1, r0, lsl #1
   8:   e12fff1e    bx  lr