我被指派将此程序转换为臂组件v8。
int power(int x, int y){
if (x == 0){
return 0;
}
else if (y < 0){
return 0;
}
else if (y == 0){
return 1;
}
else {
return x * power(x, y - 1);
}
}
虽然我对ARM汇编语言不是很熟悉,但我想知道从哪里开始。
我试图对此进行一些研究,但最终在互联网上发现的关于ARM的信息很少。
魔术命令是arm-linux-gnueabi-gcc -S -O2 -march=armv8-a power.c
。
- 我使用了
arm-linux-gnueabi-gcc
,因为我在X86-64机器上工作,而gcc
没有可用的ARM目标。如果你在手臂系统上,你应该能够使用常规的gcc
。否则,它会出错,但不会造成伤害 -S
告诉gcc输出程序集-O2
是可选的,只是有助于稍微优化代码,并减少结果中的调试混乱-march=armv8-a
告诉它在编译时使用ARMv8目标。我有点武断地选择了armv8-a
。根据文档,所有ARM v8都是armv8-a
、armv8.1-a
、armv8.2-a
、armv8.3-a
、armv8.4-a
、armv8.5-a
、armv8.6-a
、armv8-m.base
、armv8-m.main
和armv8.1-m.main
。我不知道有什么不同,所以你可能想选择一个不同的power.c
只是告诉它要编译哪个文件。由于我们没有指定输出文件(例如:-o output.asm
(,因此程序集将输出到power.s
如果您不是在使用常规gcc
提供所需目标的arm
计算机上进行编译,则可以使用arm-linux-gnueabi-gcc
。如果你没有安装,你可以用安装
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabi binutils-arm-linux-gnueabi
输出
如果有人好奇,这是我在机器上试用时收到的输出。
.arch armv8-a
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 2
.eabi_attribute 34, 1
.eabi_attribute 18, 4
.file "testing.c"
.text
.align 2
.global power
.syntax unified
.arm
.fpu softvfp
.type power, %function
power:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
clz r2, r0
mov r3, r0
lsr r2, r2, #5
orrs r2, r2, r1, lsr #31
bne .L4
cmp r1, #0
mov r0, #1
bxeq lr
.L3:
subs r1, r1, #1
mul r0, r3, r0
bne .L3
bx lr
.L4:
mov r0, #0
bx lr
.size power, .-power
.ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
.section .note.GNU-stack,"",%progbits
我该怎么开始呢
以下是我如何解决这个问题的思考过程。看看这个问题,我可以看出它可能分为两部分:
如何将该代码编译为程序集
对于第一部分,我找到了这个答案,它提供了命令
gcc -S -fverbose-asm -O2 foo.c
。测试后,我决定删除-fverbose-asm
,因为它似乎只会给这么小的程序带来混乱。如何将编译器目标设置为ARM v8
在谷歌上快速搜索后,我发现
gcc
允许您使用-march=xxx
指定目标体系结构。我的下一步是找到一个可以从中选择的ARM体系结构列表。在找到gcc.gnu.org/onlinedocs/gcc/ARM-Options.html后,我选择了armv8-a
,因为它听起来最正确。当我尝试它时,gcc
告诉我找不到目标架构。这并不奇怪,因为我使用的是x86-64,而且编译器通常带有兼容的目标,以减少所需的空间。我知道这可能意味着我需要识别提供手臂目标的apt
包,所以我四处搜索,直到找到这个答案,这个答案填补了我需要的其余信息。
编译器资源管理器就是这种简单情况下的朋友。
ARMv8-Clang汇编,带有编译器选项-O1,用于保持递归:
# Compilation provided by Compiler Explorer at https://godbolt.org/
power(int, int): // @power(int, int)
stp x29, x30, [sp, #-32]! // 16-byte Folded Spill
str x19, [sp, #16] // 8-byte Folded Spill
mov x29, sp
mov w19, w0
mov w0, wzr
cbz w19, .LBB0_5
tbnz w1, #31, .LBB0_5
cbz w1, .LBB0_4
sub w1, w1, #1
mov w0, w19
bl power(int, int)
mul w0, w0, w19
b .LBB0_5
.LBB0_4:
mov w0, #1
.LBB0_5:
ldr x19, [sp, #16] // 8-byte Folded Reload
ldp x29, x30, [sp], #32 // 16-byte Folded Reload
ret
带有编译器选项-O1的ARM GCC(linux(程序集,用于保持递归:
# Compilation provided by Compiler Explorer at https://godbolt.org/
power(int, int):
push {r4, lr}
mov r4, r0
clz r0, r0
lsrs r0, r0, #5
orrs r3, r0, r1, lsr #31
it ne
movne r0, #0
beq .L6
.L1:
pop {r4, pc}
.L6:
movs r0, #1
cmp r1, #0
beq .L1
subs r1, r1, #1
mov r0, r4
bl power(int, int)
mul r0, r4, r0
b .L1
ARM GCC(none(带有编译器选项-O1的程序集,用于保持递归:
# Compilation provided by Compiler Explorer at https://godbolt.org/
power(int, int):
push {r4, lr}
mov r4, r0
rsbs r0, r0, #1
movcc r0, #0
orrs r3, r0, r1, lsr #31
movne r0, #0
beq .L6
.L1:
pop {r4, lr}
bx lr
.L6:
cmp r1, #0
moveq r0, #1
beq .L1
sub r1, r1, #1
mov r0, r4
bl power(int, int)
mul r0, r4, r0
b .L1
带有编译器选项-O1的ARM64 GCC程序集,用于保持递归:
# Compilation provided by Compiler Explorer at https://godbolt.org/
power(int, int):
cmp w1, 0
ccmp w0, 0, 4, ge
bne .L9
mov w0, 0
ret
.L9:
stp x29, x30, [sp, -32]!
mov x29, sp
str x19, [sp, 16]
mov w19, w0
mov w0, 1
cbnz w1, .L10
.L1:
ldr x19, [sp, 16]
ldp x29, x30, [sp], 32
ret
.L10:
sub w1, w1, #1
mov w0, w19
bl power(int, int)
mul w0, w19, w0
b .L1