We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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
$ 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 SeriousRatingSeriousRating: file format elf32-littlearmDisassembly 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 0x0000000000008088 <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
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
$ 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)
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:." ./TestLibSeriousBooh
$ adb shell /data/local/tmp
(remote)
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.