0

I'm working in a C file, which is something like this:

    #define v2      0x560000a0
    int main(void)
    {
        long int v1;
        v1 = ioread32(v2);
        return 0;
    }

and I've extracted this part to write it in assembly:

int main ()
{
    extern v1,v2;
    v1=ioread32(v2);
    return 0;
}

I'm trying to write the value of v2 in v1 using assembly code for armv4. Using

arm-linux-gnueabi-gcc -S -march=armv4 assembly_file.c

I get this code:

.arch armv4
.eabi_attribute 27, 3
.fpu vfpv3-d16
.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, 6
.eabi_attribute 34, 0
.eabi_attribute 18, 4
.file   "txind-rsi.c"
.text
.align  2
.global main
.type   main, %function

main:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
stmfd   sp!, {fp, lr}
add fp, sp, #4
ldr r3, .L2
ldr r3, [r3, #0]
mov r0, r3
bl  ioread32
mov r2, r0
ldr r3, .L2+4
str r2, [r3, #0]
mov r3, #0
mov r0, r3
sub sp, fp, #4
ldmfd   sp!, {fp, lr}
bx  lr

.L3:
.align  2

.L2:
.word   v1
.word   v2
.size   main, .-main
.ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section    .note.GNU-stack,"",%progbits

I use that code to put it back inside the C file this way:

asm volatile(
    "stmfd  sp!, {fp, lr}\n"
    "add    fp, sp, #4\n"
    "ldr    r3, =v1\n"
    "ldr    r3, [r3, #0]\n"
    "mov    r0, r2\n"
    "ldr    r3, =v2\n"
    "str    r2, [r3, #0]\n"
    "sub    sp, fp, #4\n"
    "ldmfd  sp!, {fp, lr}\n"
    "bx lr"
);

The code doesn't do anything.

In fact, it stops the target working. Does anyones know why?

EDITED: After reading your answers I have another question: How would I put a constant value in a register?. The code in C would be this:

#define v2      0x560000a0
int main(void)
{
    long int value = 0x0000ffff;
    long int v1;
    v1 = ioread32(v2);
    iowrite32(v2,value);
    return 0;
}

I've tried this:

asm volatile("mov r3, #value");

and I get an assembler message: "value symbol is in a different section"; I've also tried

asm volatile("mov r3, #0x0000ffff);

and the assembler message is: "invalid constant(ffff) after fixup". And after reading this: Invalid constant after fixup? I don't know how I can put that value into r3, as it seems I can't do it with mov.I'm using armv4, not armv7. And this solution proposed in the link, doesn't work for me:

asm volatile("ldr   r3, =#0000ffff\n");
Community
  • 1
  • 1
Trouble-lling
  • 333
  • 5
  • 15
  • 2
    The **really** interesting part is missing: The C source you started with (`assembly_file.c`)... – DevSolar Apr 01 '14 at 10:00
  • 1
    ...and you're still missing a compilable version of your final C file. Or did you actually put that `asm volatile` line into a .c file in isolation and expected it to do anything? – DevSolar Apr 01 '14 at 10:11
  • No I use it inside a C file but it's quite long and I only wanted to translate the C instruction: v2= readl(v1) into assembly code for armv4. – Trouble-lling Apr 01 '14 at 10:21
  • 2
    ...but it doesn't work, and we can't reproduce the results you are seeing because of missing information. Shorten your code until you have a minimal example still exhibiting the observed behaviour, then post that. This is debugging 101, really. (As I said, I don't know about ARM assembly. But does it matter that your inline assembly is missing a couple of lines, compared to the disassembly?) – DevSolar Apr 01 '14 at 10:31
  • 1
    Show 10 lines before and 10 lines after your `asm volatile` statement. – Jabberwocky Apr 01 '14 at 10:57

2 Answers2

2

There are no problems with your code, bx lr is the proper way to terminate main, no issue there. Your code is most likely crashing due to the address you are accessing, it is probably not an address you are allowed to access...

#define v2      0x560000a0
    int main(void)
    {
        long int v1;
        v1 = ioread32(v2);
        return 0;
    }

if you optimize on the C compile step you can see a cleaner, simpler version

00000000 <main>:
   0:   e92d4008    push    {r3, lr}
   4:   e59f0008    ldr r0, [pc, #8]    ; 14 <main+0x14>
   8:   ebfffffe    bl  0 <ioread32>
   c:   e3a00000    mov r0, #0
  10:   e8bd8008    pop {r3, pc}
  14:   560000a0    strpl   r0, [r0], -r0, lsr #1

which is not hard to implement in asm.

.globl main
main:
    push {r3,lr}
    ldr r0,=0x560000A0
    bl ioread32
    mov r0,#0
    pop {r3,pc}

assembled and disassembled

00000000 <main>:
   0:   e92d4008    push    {r3, lr}
   4:   e59f0008    ldr r0, [pc, #8]    ; 14 <main+0x14>
   8:   ebfffffe    bl  0 <ioread32>
   c:   e3a00000    mov r0, #0
  10:   e8bd8008    pop {r3, pc}
  14:   560000a0    strpl   r0, [r0], -r0, lsr #1

you had simplified the code to the point that v1 becomes dead code, but the function call cannot be optimized out, so the return is discarded.

if you dont use main but create a separate function that returns

#define v2      0x560000a0
    long int fun(void)
    {
        long int v1;
        v1 = ioread32(v2);
        return v1;
    }

...damn...tail optimization:

00000000 <fun>:
   0:   e59f0000    ldr r0, [pc]    ; 8 <fun+0x8>
   4:   eafffffe    b   0 <ioread32>
   8:   560000a0    strpl   r0, [r0], -r0, lsr #1

Oh well. You are on the right path, see what the C compiler generates then mimic or modify that. I suspect it is your ioread that is the problem and not the outer structure (why are you doing a 64 bit thing with a 32 bit read, maybe that is the problem long it is most likely going to be implemented as 64 bit).

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • The "64bit thing with a 32 bit read" is the ioread32(v2), with v2 being a long integer?. In fact, it's not a long integer in the main program. It's defined as a u32 variable. Sorry for the change. I don't know how to do the optimization (is a -On modifier?) and the assembly and disassembly. Anyway my new problem is that I can't write a value such as 0x0000ffff with a iowrite32 instruction. I can't use ldr and mov doesn't work either. I've edited the message – Trouble-lling Apr 02 '14 at 08:08
  • where did you get this hard coded address? you are quite likely to crash if this is running on top of an operating system...If not on an operating system the this becomes quite simple, just an ldr, if ldr isnt working for you it isnt ldr that is the problem... – old_timer Apr 02 '14 at 13:39
  • While `bx lr` is a proper way to end the function, it only works right if you clean up everything you did in the prologue. Given that in this case the compiler generates the prologue, you must leave it to clean stuff up. Your own example illustrates that the compiler generated a `push {r3, lr}`. Now imagine if the function body included an asm block that had `bx lr` in it, this push wouldn't be cleaned up from the stack. – Jester Apr 02 '14 at 21:54
1

The bx lr at the end would try to return from the current function. You probably don't want that. I guess that is also the reason for the crash, given that you don't let the compiler undo whatever setup it has done in the function prologue.

Also, in your asm block you don't use any locals so you don't need to adjust the stack pointer, and you don't need a new stack frame either. The mov r0, r2 is also broken because you have loaded the value into r3. You can delete the mov if you just load directly into whatever register you want. Furthermore, in gcc inline asm you should tell the compiler what registers you modify. Not doing so can also lead to a crash because you might overwrite values the compiler relies upon.

Not sure what's the point in doing this in assembly. If you insist on that, the following should work somewhat better:

asm volatile(
    "ldr    r3, =v1\n"
    "ldr    r2, [r3, #0]\n"
    "ldr    r3, =v2\n"
    "str    r2, [r3, #0]\n" ::: "r2", "r3"
);
Jester
  • 56,577
  • 4
  • 81
  • 125
  • My C code has to use iowrite32 and ioread32 for several memory positions. I posted just one of this instructions to simplify the length of the assembly code. I guess the bx lr instruction is for the return 0 at the end of the file I compiled with arm-linux-gnueabi-gcc.So, if I want to read a value from a memory position indicated by v2 and store it in v1 I should do what you've written, shouldn't I? And if I want to write a value in a memory position, I only have to load the value in a register and then write it in the correct position? I can't find a good source for inline arm4 asm code in C – Trouble-lling Apr 01 '14 at 12:34
  • But why do you use asm for this? Why not just simple C? – Jester Apr 01 '14 at 12:37
  • 1
    Because I have been told so. I have to learn to include armv4 assembly code in C. All the sources of information I find aren't very clear and don't have examples from which I can learn. Could you please suggest some book or web where I can study it? – Trouble-lling Apr 01 '14 at 12:44