This assembly code makes nothing

2019-09-07 03:50发布

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");

标签: c assembly arm
2条回答
来,给爷笑一个
2楼-- · 2019-09-07 04:23

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"
);
查看更多
甜甜的少女心
3楼-- · 2019-09-07 04:28

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).

查看更多
登录 后发表回答