This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

[ELF/Thumb] Is it possible to create library procedures in Thumb-mode only ?

Greetings,

In my journey to learn ARM assembly using Android (Linux) systems, I'm currently playing with Thumb mode.

I'm currently testing if it is possible to write (ELF) library procedures entirely in Thumb. ATM, such tests only led me to Segmentation faults or Illegal Instruction errors.

So I'm wondering if it is possible to write an exported library procedure entirely in Thumb mode.

So, here's a contrived example of a working program listing, named SeriousRating.s, using an internal Thumb mode procedure call :

.data

ratings:
  .ascii "Booh\n\0Yay!\n"

.text

.syntax unified
.globl _start
_start:
  mov r0, #0 // #1 if we got payed by the rated establishment !
  blx seriousrating
  mov r0, #0
  mov r7, #1
  svc #0

  
// Print Yay if the argument is positive
// Else print booh
.thumb
seriousrating:
  push {lr}
  ldr r1, =ratings
  cbz r0, .Lprint
  adds r1, #6
.Lprint:
  movs r0, #1 // fd : stdout
  movs r2, #5 // size : The two strings have the same size
  movs r7, #4 // Linux : sys_write
  svc #0
  pop {pc}

If I compile this example like this :

$ armv7a-hardfloat-linux-gnueabi-as -o SeriousRating.o SeriousRating.s

$ armv7a-hardfloat-linux-gnueabi-ld.gold -o SeriousRating SeriousRating.o

And run it on my phone like this :

$ adb push SeriousRating /data/local/tmp && adb shell /data/local/tmp/SeriousRating

It works :

Booh

And objdump clearly reveals that the procedure was compiled in thumb mode :

LANG=C armv7a-hardfloat-linux-gnueabi-objdump -d SeriousRating

SeriousRating:     file format elf32-littlearm

Disassembly of section .text:

00008074 <_start>:

    8074:       e3a00000        mov     r0, #0

    8078:       fa000002        blx     8088 <seriousrating>

    807c:       e3a00000        mov     r0, #0

    8080:       e3a07001        mov     r7, #1

    8084:       ef000000        svc     0x00000000

00008088 <seriousrating>:

    8088:       b500            push    {lr}

    808a:       4904            ldr     r1, [pc, #16]   ; (809c <seriousrating+0x14>)

    808c:       b100            cbz     r0, 8090 <seriousrating+0x8>

    808e:       3106            adds    r1, #6

    8090:       2001            movs    r0, #1

    8092:       2205            movs    r2, #5

    8094:       2704            movs    r7, #4

    8096:       df00            svc     0

    8098:       bd00            pop     {pc}

    809a:       0000            .short  0x0000

    809c:       000090a0        .word   0x000090a0

However, if I try to use it as a library, splitting it like follows, it fails :

LibSerious.s

.data

ratings:
  .ascii "Booh\n\0Yay!\n"

// Print Yay if the argument is positive
// Else print booh
.text

.syntax unified
.thumb
.globl seriousrating
seriousrating:
  push {lr}
  ldr r1, =ratings
  cbz r0, .Lprint
  adds r1, #6
.Lprint:
  movs r0, #1 // fd : stdout
  movs r2, #5 // size : The two strings have the same size
  movs r7, #4 // Linux : sys_write
  svc #0
  pop {pc}

TestLibSerious.s

.syntax unified
.globl _start
_start:
  mov r0, #0
  bl seriousrating
  mov r0, #0
  mov r7, #1
  svc #0

And then compile it like his :

$ armv7a-hardfloat-linux-gnueabi-as -o LibSerious.o LibSerious.s

$ armv7a-hardfloat-linux-gnueabi-as -o TestLibSerious.o TestLibSerious.s

$ armv7a-hardfloat-linux-gnueabi-ld.gold -shared --dynamic-linker=/system/bin/linker --hash-style=sysv -o libserious.so LibSerious.o

$ armv7a-hardfloat-linux-gnueabi-ld.gold --dynamic-linker=/system/bin/linker --hash-style=sysv -o TestLibSerious TestLibSerious.o libserious.so

$ adb push TestLibSerious /data/local/tmp

$ adb push libserious.so /data/local/tmp

$ adb shell

(Android shell)

$ cd /data/local/tmp

$ LD_LIBRARY_PATH="$LD_LIBRARY_PATH:." ./TestLibSerious

I get :

Illegal Instruction

(Shell return code : 132)

However, if I edit LibSerious.s, remove ".thumb" to get ARM code, replace the cbz by "cmp r0, #0" - "beq .Lprint" and recompile, it works :

.data

ratings:
  .ascii "Booh\n\0Yay!\n"

// Print Yay if the argument is positive
// Else print booh
.text

.syntax unified
.globl seriousrating
seriousrating:
  push {lr}
  ldr r1, =ratings
  cmp r0, #0
  beq .Lprint
  adds r1, #6
.Lprint:
  movs r0, #1 // fd : stdout
  movs r2, #5 // size : The two strings have the same size
  movs r7, #4 // Linux : sys_write
  svc #0
  pop {pc}

$ armv7a-hardfloat-linux-gnueabi-as -o LibSerious.o LibSerious.s

$ armv7a-hardfloat-linux-gnueabi-ld.gold -shared --dynamic-linker=/system/bin/linker --hash-style=sysv -o libserious.so LibSerious.o

$ adb push libserious.so /data/local/tmp

$ adb shell /data/local/tmp

(remote)

$ cd /data/local/tmp

$ LD_LIBRARY_PATH="$LD_LIBRARY_PATH:." ./TestLibSerious

Booh

So the question is : Is it possible to write an exported library procedure in Thumb ? If yes how to call it correctly ? Knowing that the caller do not know that procedure is written in Thumb.

Parents
  • For the record, the only alternative solution I found is to start the procedure in ARM mode and then do a blx jump to a label starting the .thumb code, just after the prologue.

    The epilogue stays unchanged.

    Something like this :

    .syntax unified
    .globl seriousrating
    seriousrating:
      push {lr}
      blx .Lstartsr
      .thumb
    .Lstartsr: // Thumb code
      ldr r1, =ratings
      cbz r0, .Lprint
      adds r1, #6
    .Lprint:
      movs r0, #1 // fd : stdout
      movs r2, #5 // size : The two strings have the same size
      movs r7, #4 // Linux : sys_write
      svc #0
      pop {pc} // The ARM processor auto configure the interpretation mode when you move an address to pc
    
    
Reply
  • For the record, the only alternative solution I found is to start the procedure in ARM mode and then do a blx jump to a label starting the .thumb code, just after the prologue.

    The epilogue stays unchanged.

    Something like this :

    .syntax unified
    .globl seriousrating
    seriousrating:
      push {lr}
      blx .Lstartsr
      .thumb
    .Lstartsr: // Thumb code
      ldr r1, =ratings
      cbz r0, .Lprint
      adds r1, #6
    .Lprint:
      movs r0, #1 // fd : stdout
      movs r2, #5 // size : The two strings have the same size
      movs r7, #4 // Linux : sys_write
      svc #0
      pop {pc} // The ARM processor auto configure the interpretation mode when you move an address to pc
    
    
Children