EmbDev.net

Forum: ARM programming with GCC/GNU tools ARM mode inline assembly in Thumb mode C file?


von Aaron D. (adsouzp)


Attached files:

Rate this post
useful
not useful
hello:

one small question regarding use of ARM inline assembly code in a
C file that has been compiled for Thumb mode.

is it possible to use ARM inline assembly code from within a C file
that has been compiled for Thumb mode and Thumb interworking?

how this is done is described on this page:
http://www.devrs.com/gba/files/asmc.txt

i have a C file that has been compiled for Thumb mode. in it, i am
using ARM inline assembly code. apparently, GCC issues no error
message but forcibly converts the ARM code into Thumb code.

i think that GCC requires an entire file to be in either Thumb mode
or ARM mode, but i am not sure. is that true?

the C code that is compiled into Thumb is:

void function_f( void )
{
   asm volatile
   (
     ".align                \n\t"
     ".arm                  \n\t"
     "mrs     r0,     cpsr  \n\t"
     "msr     cpsr_c, r0    \n\t"
     "pop     { r0 }"
   );
}

the C code is compiled with:
arm-elf-gcc -mlittle-endian -mcpu=arm7tdmi -march=armv4t    \
             -mthumb-interwork -mthumb -mno-tpcs-frame .....


in the inline assembly code, if i do not use ".arm", i get compiler
errors.

is it possible to use ARM assembly code from within a C file that
has been compiled for Thumb and Thumb interworking?

Aaron

=============================== SOURCE CODE
================================

Makefile
--------

CC            = arm-elf-gcc
TARGET_ARCH   = -mlittle-endian -mcpu=arm7tdmi -march=armv4t
-mthumb-interwork
TARGET_ARCH  += -mthumb -mno-tpcs-frame

all:  test
  arm-elf-objdump -S -D test > test.lst

clean:
  rm -f test test.o function.o


test.c
------

void function_f( void )
{
  asm volatile
  (
    ".align                \n\t"
    ".arm                  \n\t"
    "mrs     r0,     cpsr  \n\t"
    "msr     cpsr_c, r0    \n\t"
    "pop     { r0 }"
  );
}

int main( void )
{
  function_f();
  return 0;
}

von Aaron D. (adsouzp)


Rate this post
useful
not useful
hello folks:

in the last post, i forgot to show the generated code.
here it is. as you can see, ".arm" in inline assembly
generates "0000" in the output.

00008194 <function_f>:
    8194:  b580        push  {r7, lr}
    8196:  af02        add  r7, sp, #8
    8198:  0000        lsls  r0, r0, #0
    819a:  e10f        b.n  83bc <wrap+0x10>
    819c:  f000 e121   blx  4083e0 <_stack+0x3883e0>
    81a0:  0001        lsls  r1, r0, #0
    81a2:  e8bd 46bd   ldmia.w  sp!, {r0, r2, r3, r4, r5, r7, r9, sl,
lr}
    81a6:  b082        sub  sp, #8
    81a8:  bc80        pop  {r7}
    81aa:  bc01        pop  {r0}
    81ac:  4700        bx  r0

von Giovanni D. (gdisirio)


Rate this post
useful
not useful
Aaron D'souza wrote:
> hello:
>
> one small question regarding use of ARM inline assembly code in a
> C file that has been compiled for Thumb mode.
> ...

Hello, I posted an answer on usenet already.

Anyway you just need to put a ".code 16" after the arm code in order to
return to thumb mode or the assembler will get confused.

regards,
Giovanni
---
ChibiOS/RT http://chibios.sourceforge.net

von Aaron D. (adsouzp)


Rate this post
useful
not useful
hello Giovanni:

Giovanni Di Sirio wrote:
> Hello, I posted an answer on usenet already.

i saw your quick reply. thank you very much.

> Anyway you just need to put a ".code 16" after the arm code in order to
> return to thumb mode or the assembler will get confused.

that's the trick that i did not know about. how do i know that the
assembler is going to get confused?

anyway, as i said on Usenet, i have also received a reply from Nick
Clifton, which i will now post. i will also post the complete working
solution that i use.

Aaron

von Aaron D. (adsouzp)


Rate this post
useful
not useful
hello ffolks:

here is a reply from Nick Clifton, which is really illuminating. pls
read it carefully. i will also post the complete working solution, if i
can get permission from my boss.

-------- Original Message --------
Subject  : Re: RESEND : QUERY : ARM inline code in Thumb file?
Date     : Wed 27 Aug 2008 10:37:23 +0100
From     : Nick Clifton @ RedHat
To       : Aaron P. D'Souza

Hi Aaron,

> is it possible to use ARM assembly code from within a C file that
> has been compiled for Thumb and Thumb interworking?

Yes.

> i have a C file that has been compiled for Thumb mode. in it, i am
> using ARM inline assembly code. apparently, GCC issues no error
> message but forcibly converts the ARM code into Thumb code.

Highly unlikely.  What is more likely is that you need to be careful
about how you insert the ARM code.

> the C code that is compiled into Thumb is:
>
> void function_f( void )
> {
>    asm volatile
>    (
>      ".align                \n\t"
>      ".arm                  \n\t"
>      "mrs     r0,     cpsr  \n\t"
>      "msr     cpsr_c, r0    \n\t"
>      "pop     { r0 }"
>    );
> }

There are two problems with the above code:

  1. You do not switch back to thumb mode at the end of the ARM code
fragment.  Gcc passes the contents of the asm() directory on to the
assembler - it does not try to parse it and discover that you are
sneakily switching into ARM mode...

  2. You have the .arm directive without a nearby label to hang it on.
 The .arm (and .thumb) directives need a label because the changes
between instruction sets is encoded into attributes of the labels, thus
allowing the linker and disassembler to know when instruction sets have
changed.

ie. please try this:

void function_f( void )
{
   asm volatile
   (
     ".align                \n"
     "__f_into_arm:\n\t"
     ".arm                  \n\t"
     "mrs     r0,     cpsr  \n\t"
     "msr     cpsr_c, r0    \n\t"
     "pop     { r0 }        \n"
     "__f_from_arm:\n\t"
     ".thumb"
   );
}

Cheers
  Nick

von Aaron D. (adsouzp)


Rate this post
useful
not useful
hello:

Nick Clifton wrote:
>> void function_f( void )
>> {
>>    asm volatile
>>    (
>>      ".align                \n\t"
>>      ".arm                  \n\t"
>>      "mrs     r0,     cpsr  \n\t"
>>      "msr     cpsr_c, r0    \n\t"
>>      "pop     { r0 }"
>>    );
>> }
>
> There are two problems with the above code:
>
>   1. You do not switch back to thumb mode at the end of the ARM code
> fragment.  Gcc passes the contents of the asm() directory on to the
> assembler - it does not try to parse it and discover that you are
> sneakily switching into ARM mode...
>
>   2. You have the .arm directive without a nearby label to hang it on.
>  The .arm (and .thumb) directives need a label because the changes
> between instruction sets is encoded into attributes of the labels, thus
> allowing the linker and disassembler to know when instruction sets have
> changed.
>
> ie. please try this:
>
> void function_f( void )
> {
>    asm volatile
>    (
>      ".align                \n"
>      "__f_into_arm:\n\t"
>      ".arm                  \n\t"
>      "mrs     r0,     cpsr  \n\t"
>      "msr     cpsr_c, r0    \n\t"
>      "pop     { r0 }        \n"
>      "__f_from_arm:\n\t"
>      ".thumb"
>    );
> }

actually that does not work also. look at the translated code:
00008194 <function_f>:
    8194:  b580        push  {r7, lr}
    8196:  af02        add  r7, sp, #8

00008198 <__f_into_arm>:
    8198:  0000        lsls  r0, r0, #0
    819a:  e10f        b.n  83bc <wrap+0x10>
    819c:  f000 e121   blx  4083e0 <_stack+0x3883e0>
    81a0:  0001        lsls  r1, r0, #0
    81a2:  e8bd 46bd   ldmia.w  sp!, {r0, r2, r3, r4, r5, r7, r9, sl,
lr}

000081a4 <__f_from_arm>:
    81a4:  b08246bd   strlth  r4, [r2], sp
    81a8:  bc01bc80   stclt  12, cr11, [r1], {128}
    81ac:  00004700   andeq  r4, r0, r0, lsl #14

von Giovanni D. (gdisirio)


Rate this post
useful
not useful
Aaron D'souza wrote:
> hello Giovanni:
>
> Giovanni Di Sirio wrote:
>> Hello, I posted an answer on usenet already.
>
> i saw your quick reply. thank you very much.
>
>> Anyway you just need to put a ".code 16" after the arm code in order to
>> return to thumb mode or the assembler will get confused.
>
> that's the trick that i did not know about. how do i know that the
> assembler is going to get confused?
>
> anyway, as i said on Usenet, i have also received a reply from Nick
> Clifton, which i will now post. i will also post the complete working
> solution that i use.
>
> Aaron

Please look at my last reply, that example includes the switch to arm
mode and back to thumb mode.

This is the code I posted there:

void function_f( void )
{
  asm volatile
  (
    ".balign 4             \n\t"
    "mov     r0, pc        \n\t"
    "bx      r0            \n\t"
    ".code 32              \n\t"
    "mrs     r0, cpsr      \n\t"
    "msr     cpsr_c, r0    \n\t"
    "add     r0, pc, #1    \n\t"
    "bx      r0            \n\t"
    ".code 16              \n\t"
  );
}

which generates:

function_f:
        .balign 4
        mov     r0, pc        // jumps into ARM mode
        bx      r0
        .code 32
        mrs     r0, cpsr      // ARM code starting here
        msr     cpsr_c, r0
        add     r0, pc, #1    // returns to thumb code
        bx      r0
        .code 16
        bx      lr            // thumb code continues here

regards,
Giovanni
---
ChibiOS/RT http://chibios.sourceforge.net

von Aaron D. (adsouzp)


Attached files:

Rate this post
useful
not useful
hello Giovanni:

thank you for being so helpful. i am truly indebted to you.

i tried your code and that also did not work. are you sure you are
compiling the C file into Thumb mode? pls find attached the C file
and the Makefile. pls try those.

also, the version of GNUARM that i am using is 4.1.1.
$ arm-elf-gcc --version
arm-elf-gcc (GCC) 4.1.1

Giovanni Di Sirio wrote:
> Please look at my last reply, that example includes the switch to arm
> mode and back to thumb mode.
>
> This is the code I posted there:
>
> void function_f( void )
> {
>   asm volatile
>   (
>     ".balign 4             \n\t"
>     "mov     r0, pc        \n\t"
>     "bx      r0            \n\t"
>     ".code 32              \n\t"
>     "mrs     r0, cpsr      \n\t"
>     "msr     cpsr_c, r0    \n\t"
>     "add     r0, pc, #1    \n\t"
>     "bx      r0            \n\t"
>     ".code 16              \n\t"
>   );
> }
>
> which generates:
>
> function_f:
>         .balign 4
>         mov     r0, pc        // jumps into ARM mode
>         bx      r0
>         .code 32
>         mrs     r0, cpsr      // ARM code starting here
>         msr     cpsr_c, r0
>         add     r0, pc, #1    // returns to thumb code
>         bx      r0
>         .code 16
>         bx      lr            // thumb code continues here

i am looking at the code in the executable .ELF file, which i
disassembled
using arm-elf-objdump. pls take a look at the Makefile attached.

with your code, this is what is disassembled from the .ELF file.

00008194 <function_f>:
    8194:  b580        push  {r7, lr}
    8196:  af02        add  r7, sp, #8
    8198:  4678        mov  r0, pc
    819a:  4700        bx  r0
    819c:  0000        lsls  r0, r0, #0
    819e:  e10f        b.n  83c0 <wrap+0xc>
    81a0:  f000 e121   blx  4083e4 <_stack+0x3883e4>
    81a4:  0001        lsls  r1, r0, #0
    81a6:  e28f        b.n  86c8 <_stat+0x1c>
    81a8:  ff10 e12f   undefined
    81ac:  46bd        mov  sp, r7
    81ae:  b082        sub  sp, #8
    81b0:  bc80        pop  {r7}
    81b2:  bc01        pop  {r0}
    81b4:  4700        bx  r0

von Giovanni D. (gdisirio)


Rate this post
useful
not useful
> 00008194 <function_f>:
>     8194:  b580        push  {r7, lr}
>     8196:  af02        add  r7, sp, #8
>     8198:  4678        mov  r0, pc
>     819a:  4700        bx  r0
>     819c:  0000        lsls  r0, r0, #0
>     819e:  e10f        b.n  83c0 <wrap+0xc>
>     81a0:  f000 e121   blx  4083e4 <_stack+0x3883e4>
>     81a4:  0001        lsls  r1, r0, #0
>     81a6:  e28f        b.n  86c8 <_stat+0x1c>
>     81a8:  ff10 e12f   undefined
>     81ac:  46bd        mov  sp, r7
>     81ae:  b082        sub  sp, #8
>     81b0:  bc80        pop  {r7}
>     81b2:  bc01        pop  {r0}
>     81b4:  4700        bx  r0

Ok, I understood the problem now. The disassembler is not able to
understand when to disassemble in arm mode and when disassemble in thumb
mode, it always disassemble in thumb mode so when it disassemble the arm
code the resulting text is garbage.
I suggest that you look at the listing files generated by the assembler,
there you can see both the correct mnemonics and the binary code.

The listing of the above code is:

  18                function_f:
  19                .LFB9:
  20                  .file 1 "board.c"
  21                  .loc 1 32 0
  22                  @ lr needed for prologue
  23                  .loc 1 33 0
  24                  .balign 4
  25 0000 7846         mov     r0, pc
  26 0002 0047         bx      r0
  27                  .code 32
  28 0004 00000FE1     mrs     r0, cpsr
  29 0008 00F021E1     msr     cpsr_c, r0
  30 000c 01008FE2     add     r0, pc, #1
  31 0010 10FF2FE1     bx      r0
  32                  .code 16
  33
  34                  .loc 1 45 0
  35                  .code  16
  36                  @ sp needed for prologue
  37 0014 7047         bx  lr

Note, it is compiled using -O2 so it is a bit different (no prologue and
epilogue code).

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.