ARM C Inline assembly - LDR instruction - arm

I am working with inline assembly on RPI2(ARM arch) and I am using GCC for my compiler.
I want to compile and run the following part of code but I take an error, If anyone can help me or give me any help to fix the problem please.
Here is the part of code that I need help:
int main(void)
{
int a;
asm("PUSH {r0}");
asm("PUSH {r1}");
asm("LDR r0, =a");
asm("MOV r1, sp");
asm("STR r1, [r0]");
asm("POP {r1}");
asm("POP {r0}");
}
The error that I take is about the LDR instruction. I tried to remove the '=' or instead of the LDR command to use MOV but still does not work.

To access specific registers, you can use asm register variables, such as:
register int sp asm("sp");
__asm__ __volatile__("" : "=r" (sp));

Related

embedding ARM assembly in C language

My goal is to implement sorting algorithm using C language.
I have to make a C code that converts into least number of instructions when compiled by gcc -O0(no optimization option) in ARM machine.
So, My idea is to embed quicksort implemented in assembly directly into C code.
I referred to several following documents and tried to implement my goal.
However, I don't know how to put intarray into my assembly function 'QuickSort' as a parameter.
Reference
1.https://en.wikibooks.org/wiki/Algorithm_Implementation/Sorting/Quicksort#ARM_Assembly
2.http://forum.falinux.com/zbxe/index.php?mid=lecture_tip&comment_srl=517498&sort_index=readed_count&order_type=asc&l=fr&page=58&document_srl=567970 (sorry for non-english website)
I'm newbie in assembly.
Please help me..
#include <stdio.h>
#include <stdint.h>
int Quicksort(uint32_t intarray[]);
asm(
".global Quicksort\n\
Quicksort:\n\
qsort:\n\
stmfd sp!,{r4, r6, lr} \n\
mov r6,r2 \n\
qsort_tailcall_entry:\n\
sub r7,r6,r1\n\
cmp r7,#1\n\
ldmlefd sp!,{r4,r6,pc}\n\
ldr r7,[r0,r1,asl#2]\n\
add r2,r1,#1\n\
mov r4,r6\n\
partition_loop:\n\
ldr r3,[r0, r2, asl #2]\n\
cmp r3,r7\n\
addle r2,r2, #1\n\
ble partition_test\n\
sub r4,r4, #1\n\
ldr r5,[r0, r4, asl #2]\n\
str r5,[r0, r2, asl #2]\n\
str r3,[r0, r4, asl #2]\n\
partition_test:\n\
cmp r2,r4\n\
blt partition_loop\n\
partition_finish:\n\
sub r2,r2,#1\n\
ldr r3,[r0,r2,asl #2]\n\
str r3,[r0,r1,asl #2]\n\
str r7,[r0,r2,asl #2]\n\
bl qsort\n\
mov r1,r4\n\
b qsort_tailcall_entry\n\
"
);
int main(void){
uint32_t intarray[10] = {5,2,5,1,7,5,7,2,3,8};
Quicksort(intarray);
return 0;
}
Since you mentioned that you are compiling with gcc, you could use the gcc asm extension (as the name says, it's a gcc extension and might not be compatible with other compilers). Take a look at basic asm and extended asm. Since you will probably be accessing data from your C code, I advise you to stick with the advanced version which lets you specify memory operands.

Is it possible to access hardware register through inline assembly

I am trying to access hardware register on a Broadcom ARM processsor through inline assemble. I have accessed hardware regiters through bare metal programming, but now I am trying to incorporate those bare metal programming codes in the C file using asm. Here is my code which toggles GPIO 17 on a Raspberry Pi 2:
void main() {
__asm__(
".section .init\n\t"
".globl _start\n\t"
"_start:"
"ldr r0,=0x3F200000\n\t"
"mov r1, #1\n\t"
"lsl r1, #21\n\t"
"str r1, [r0, #4]\n\t"
"loop$:\n\t"
"mov r1, #1\n\t"
"lsl r1, #17\n\t"
"str r1, [r0, #28]\n\t"
"mov r1, #1\n\t"
"lsl r1, #17\n\t"
"str r1, [r0, #40]\n\t"
"b loop$\n\t"
);
}
but when I compile it by gcc file.c
it throws following error
/tmp/ccrfp9mv.s: Assembler messages:
/tmp/ccrfp9mv.s: Error: .size expression for main does not evaluate to a constant
You get Error: .size expression for main does not evaluate to a constant because you change sections inside a function. As you can see on the godbolt compiler explorer, the compiler will emits asm directives to calculate ELF metadata, with lines like:
.size main, .-main # size_of_main = current_pos - start_of_main
Since you switch sections inside the body of main, the distance between main and the end of main isn't known until link time, and it's not possible to get the linker to fill in this piece of metadata that late. (.size has to be an assemble-time constant, not just a link-time constant).
Like people commented, you should do the whole thing in C, e.g. with a global like
#include <stdint.h>
volatile uint32_t *const GPIO17 = (uint32_t*)0x3F200000; // address is const, contents aren't.
Presumably you need to ask the OS for access to that MMIO register. Part of the OS's job is to stop programs from talking directly to the hardware and messing up other programs that are doing the same thing at the same time.
Even if your code assembled, it won't link because your definition of _start will conflict with the one provided by the libc runtime code.
Don't try to define a function in inline asm inside another function. Write a stand-alone function if you want to do that.

ARM assembly calling a function with registers as parameters using C

I have the following ARM assembly code:
mov r0, SP
mov r1, LR
bl func
Is there a way of calling the function func using C code? something like func(SP, LR)
Thanks!
Depends on what exactly you want to do and what compiler you use.
With gcc something like this could work:
extern void func(void*, void*);
void foo()
{
int dummy[4];
func(&dummy, __builtin_return_address(0));
}
This might not always give you the exact stack pointer, though. As per godbolt it produces the following assembly code:
foo():
push {lr}
sub sp, sp, #20
mov r1, lr
mov r0, sp
bl func(void*, void*)
add sp, sp, #20
ldr pc, [sp], #4
Use output registers to place LR and SP in variables:
void *lr, *sp;
asm ("mov %0, sp" : "=r" (sp));
asm ("mov %0, lr" : "=r" (lr));
func(lr, sp);

Is there any gcc compiler primitive for "svc"?

I'm working on writing a program running on Cortex-m3.
At first I wrote an assembly file which executes 'svc'.
svc:
svc 0
bx lr
I decided to use gcc's inline asm, so I wrote it as follows, but the svc function was not inlined.
__attribute__((naked))
int svc(int no, ...)
{
(void)no;
asm("svc 0\n\tbx lr");
}
int f() {
return svc(0,1,2);
}
------------------ generated assembly ------------------
svc:
svc 0
bx lr
f:
mov r0, #0
mov r1, #1
mov r2, #2
b svc
I guess it's not inlined since it is naked, so I dropped the naked attribute and wrote like this.
int svc(int __no, ...)
{
register int no asm("r0") = __no;
register int ret asm("r0");
asm("svc 0" : "=r"(ret) : "r"(no));
return ret;
}
------------------ generated assembly ------------------
svc:
stmfd sp!, {r0, r1, r2, r3}
ldr r0, [sp]
add sp, sp, #16
svc 0
bx lr
f:
mov r0, #0 // missing instructions setting r1 and r2
svc 0
bx lr
Although I don't know why gcc adds some unnecessary stack operations, svc is good. The problem is that svc is not inlined properly, the variadic parameters were dropped.
Is there any svc primitive in gcc? If gcc does not have one, how do I write the right one?
Have a look at the syntax that is used in core_cmFunc.h which is supplied as part of the ARM CMSIS for the Cortex-M family. Here's an example that writes a value to the Priority Mask Register:
__attribute__ ((always_inline)) static inline void __set_PRIMASK(uint32_t priMask)
{
__ASM volatile ("MSR primask, %0"::"r" (priMask));
}
However, creating a variadic function like this sounds difficult.
You can use a macro like this.
#define __svc(sNum) __asm volatile("SVC %0" ::"M" (sNum))
And use it just like any compiler-primitive function, __svc(2);.
Since it is just a macro, it will only generate the provided instruction.

how to do a simple loop in ARM inline Assembly with NDK?

I'm trying to do a simple loop in ARM Assembly, but every time i run it crashes
this is the log:
01-13 15:34:21.277: A/libc(27296): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 27312 (Thread-2932)
and here is my code what am i doing wrong?
void foo(int *pIn, int *pOut) {
//pIn contains the number of iterations the loop will have
asm volatile(
"ldr r3, %[in];"
"ldr r4, %[out];"
"ldr r5, [r3];"
"loop:; "
//here would go the code inside the loop perhaps put something in output, in this case just do nothing
"subs r5, r5, #1;"
"bne loop"
:[out] "=m" (pOut)
:[in] "m" (pIn)
:"r3","r4","r5","memory"
);
}
and in Android.mk file i put the 32bit directive
LOCAL_ARM_MODE := arm
any ideas why it is crashing?
the crash only occurs when i put the loop, before this i tried moving things around and it worked perfectly fine giving output values as i expected.
the problem is solved, adding "r5" and "cc" to my clobber list made it work.
here is the working code:
void foo(int *pIn, int *pOut) {
//pIn contains the number of iterations the loop will have
asm volatile(
"ldr r3, %[in];"
"ldr r4, %[out];"
"ldr r5, [r3];"
"loop:; "
//here would go the code inside the loop perhaps put something in output, in this case just do nothing
"subs r5, r5, #1;"
"bne loop"
:[out] "=m" (pOut)
:[in] "m" (pIn)
:"r3","r4","r5","cc","memory"
);
}

Resources