Я использую toolchain GNU ARM (arm-elf-gcc). У меня есть один файл сборки и один файл c, который вызывает глобальные методы, определенные в файле сборки. Я могу успешно вызвать один метод сборки из c, но я не могу понять, как вызвать метод сборки, который сам вызывает другой метод сборки. Я хотел бы, чтобы оба метода сборки вызывались из c и находились в одном файле.Ветвление в сборе в сборе
Вот два файла. Когда я запускаю программу, она никогда не возвращается, поэтому я знаю, что есть проблема в ветвлении.
mathLib.s
@ ARM Assembler Library for absolute value
.align 2 @ Align to word boundary
.arm @ This is ARM code
.global asm_abs @ This makes it a real symbol
.global asm_two_abs @ This makes it a real symbol
@ ABS Func. Compiler just does "rsblt r0, r0, #0" but this is more fun.
asm_abs: @ Start of function definition
mov r2, #1 @ Set the least bit high in r2
mov r2, r2, lsl#31 @ Shift that bit all the way to the sign slot
orr r2, r2, r0 @ XOR with input (r0) to set ensure negative
cmp r2, r0 @ compare a for-sure neg input with input
bne asm_abs_ret @ if not equal, input was pos, so return
sub r0, r0, r0, lsl#1 @ else set input = input - (2*input)
asm_abs_ret:
mov pc, lr @ Set program counter to lr (was set by caller)
asm_two_abs: @ Start of function definition
bl asm_abs @ Should set r0 = abs(r0)
mov r2, r0 @ set r2 = r0
mov r0, r1 @ set r0 = r1
bl asm_abs @ Should set r0 = abs(r0)
add r0, r0, r2 @ set r0 = r0 + r2
mov pc, lr @ Set program counter to lr (was set by caller)
program.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
extern int asm_abs(int a);
extern int asm_two_abs(int a, int b);
int m = atoi(argv[1]);
int n = atoi(argv[2]);
int r = asm_two_abs(m, n);
printf("%d\n", r);
return 0;
}
EDIT
Вот что я придумал в конце концов
@ ARM Assembler Library for absolute value
.align 2 @ Align to word boundary
.arm @ This is ARM code
.global asm_abs @ This makes it a real symbol
.global asm_mod @ This makes it a real symbol
@ ABS Func. Compiler just does "rsblt r0, r0, #0" but this is more fun.
@int asm_abs(int a)
asm_abs: @ start of function definition
mov r2, #1 @ set the least bit high in r2
mov r2, r2, lsl#31 @ shift that bit all the way to the sign slot
orr r2, r2, r0 @ XOR with input a (r0) to set ensure negative
cmp r2, r0 @ compare a for-sure neg input with input a
bne asm_abs_ret @ if not equal, input was pos, so return
sub r0, r0, r0, lsl#1 @ else set a = a - (2*a)
asm_abs_ret:
mov pc, lr @ set program counter to lr (was set by caller)
@ Take two numbers, and return abs(a) + abs(b)
@ int asm_two_abs(int a, int b)
asm_two_abs: @ start of function definition
stmfd sp!, {r4-r6} @ push the non-scratch registers we'll use on the stack
mov r4, lr @ store link register in r4
mov r6, r1 @ store second argument b in r6
bl asm_abs @ set a (r0) = abs(a)
mov r5, r0 @ store abs(a) in r5
mov r0, r6 @ set r0 = b
bl asm_abs @ should set b = abs(b)
add r0, r0, r5 @ set r0 = abs(b) + abs(a)
mov lr, r4 @ restore link register
ldmfd sp!, {r4-r6} @ restore non-scratch registers we used
mov pc, lr @ set program counter to lr (was set by caller)
короткий ответ: инструкция bl изменяет lr (r14), первое, что делает asm_two_abs, это изменение r14, вам нужно сохранить r14, чтобы вы могли использовать его в конце (mov pc, lr) –
Я бы привыкнуть использования bx lr, а не mov pc, lr, если вы не на чем-то старше ARM7TDMI. –
Это также распространено для 'push {r4, r5, lr}' и более поздних 'pop {r4, r5, pc}'. – Renate