我已经学习了几个月的C语言,现在我开始深入研究低级语言 - ARM程序集,因此,我决定从一个非常基本的项目开始,制作一个程序集文件。阶乘函数,然后在C中调用和使用它。所以我想问一下,汇编是否可以用来定义这样一个复杂的函数,并且可以用作C中的另一个函数?如果您不介意,请给我一个.S文件的简单示例,其中函数从标准输入num1和num2加载2个数字到寄存器,计算num1 * num2并返回结果已定义并可在C源中使用文件?
谢谢你的阅读。如果这个问题很愚蠢,请至少给我一个指示,以便我可以自己跟踪并找出它。
要使用C语言中用Assembler编写的函数,您主要需要做的事情:
宣言
声明很容易,例如:
int add(int a, int b);
这是一个声明,因为它不包括函数体。当然,名称(在这种情况下添加)必须匹配。
如果在C ++中使用它,则必须添加extern "C"
:
extern "C" int add(int a, int b);
召集会议
调用约定定义了如何向函数传递参数以及从函数返回参数以及必须保存哪些寄存器。您需要熟悉细节。可以在ARM (A32) calling convention找到简化的概述。
超短且非常简化的版本是:
上述功能的简单实现是:
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函数的调试版本:在堆栈上分配空间以将a
和b
存储为局部变量,帧指针寄存器(fp)指向局部变量。最后,一切都恢复了。
大多数理智编译器编译成程序集然后调用汇编程序将其转换为对象。
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