Jumping into ARM assembly


Here's the little loop with Levi's suggestion :

Code:
        .text
        .align 2

        .global _start
_start:

        ldr r1, =text @ buffer to write
        mov r2, #13   @ buffer length
        mov r7, #4    @ system call number, 4 is 'write'

        mov r5, #5    @ set the counter to 5
_loop:

        mov r0, #1    @ file descriptor 1 - stdout
        svc 0         @ call the Linux kernel and print the text

        subs r5, #1   @ decrement the counter
        bne _loop     @ if not zero, come back to _loop

        mov r7, #1    @ exit
        svc 0


        .data
text:   .asciz "hello world!\n"
About the register reset, only r0 has to be reset because after the swi/svc 0, its value is 13.
 
 
Following dmarschal suggestion, where do I define the macros in a one file code ?
Before .global _start ?
 
As far as I can tell, no processor mode banks R0-R7.  R8-R12 are only banked in FIQ mode.  SVC mode gets a new stack pointer and link register, but you need what's in the latter IIRC.

Yeah and the rest are saved/restored by the kernel. It actually doesn't want to trash any registers as it might leave some important kernel variables in there, which would be an information leak from the kernel that's potentially useful for exploits.

Following dmarschal suggestion, where do I define the macros in a one file code ?
Before .global _start ?

Generally you can put them anywhere, it just has to be before you use it from what I remember.
 
A macro without argument is now used to display the text, and is called within the loop :

Code:
        .text
        .align 2

.macro  display_hello @	name of	the macro
        mov r0, #1    @ file descriptor 1 - stdout
        svc 0         @ call the Linux kernel and print the text
.endm

        .global _start
_start:

        ldr r1, =text @ buffer to write
        mov r2, #13   @ buffer length
        mov r7, #4    @ system call number, 4 is 'write'

        mov r5, #5    @ set the counter to 5
_loop:
        display_hello
        subs r5, #1   @ decrement the counter
        bne _loop     @ if not zero, come back to _loop

        mov r7, #1    @ exit
        svc 0

        .data
text:   .asciz "hello world!\n"
 
I tried to compare a char. Of course it didn't work. I want the loop and the program to end when I enter 'q'. 'q' isn't even loaded in r8 :/ .

Code:
	.text
	.align 2

	.global _start

_start:
        ldr r8, =quit_char @ will load the quit character into r8

_loop:
        mov r0, #0    @ file descriptor 0 - stdin
        mov r7, #3    @ system call number, 3 is 'read'
        mov r2, #1    @ buffer length
        ldr r1, =input @ will load the input into r1
        svc 0          @ call the Linux kernel and wait for the input

        cmp r1, r8    @ compare if the input == q
        bne _loop     @ if not, come back to _loop

        mov r7, #1    @ exit
        svc 0

        .data
input:     .byte 0
quit_char: .byte 'q'
 
Tetet source seems neat to read but wow, being just at the basics makes understand the first lines a challenge ^^.
 
Something I don't get, r0 r1 r2 and r7 seems to be "reserved".
I suppose it's an OS thing.

Is there any other special one ?
Which ones can I use for anything ?
 
In your code, the instruction "ldr r8, =quit_char" loads the address of quit_char into r8 - after that you can then use the instruction "ldrb r8, [r8]" to load a byte from memory (pointed to r8) to r8.

I don't know if it helps you, but I wrote a 1kB demo for GP2X (in assembler of course) - the source is here (look into the oldest version first, it's much simpler than the released version) - unfortunately there are barely any comments, so I don't know how much you can learn from it.
 
Last edited by a moderator:
Compare character. Still not working but at least, thanks to M-HT, the 113 ascii code of 'q' is loaded into r8.

Code:
	.text
	.align 2

	.global _start

_start:
       	ldr r8, =quit_char @ will load the address of quit_char into r8
        ldrb r8, [r8]  	   @ load a byte from memory (pointed to r8) to r8

_loop:
      	mov r0, #0    @ file descriptor 0 - stdin
	mov r7, #3    @ system call number, 3 is 'read'
	mov r2, #1    @ buffer length
	ldr r1, =input @ will load the input into r1
	svc 0          @ call the Linux kernel and wait for the input

	cmp r1, r8    @ compare if the input == q
	bne _loop     @ if not, come back to _loop

	mov r7, #1    @ exit
	svc 0

	.data
input:       .byte 0
quit_char:   .byte 'q'
Will take a look at your code, thx.
I read all tetet code, the game engine is too complicated for me, but the macro thing was helpful.
 
The instruction "ldr r1, =input" also loads address of input into r1, so you must load the value from memory and then compare it to r8 (for example "ldrb r0, [r1]" and "cmp r0, r8" instead of "cmp r1, r8").
 
 
Last edited by a moderator:
Indeed, although in case it isn't clear (or maybe it was just me) the initial setting of r1 to the address of =input is deliberate - it's for the read syscall.  After that, and before you do the compare, you need to load what r1 points to into another register, as you suggest.
 
Well it works with ldrb r1, [r1] and cmp r1, r8.
Something curious, when the program stops, it's like i've pressed "enter" :

~/devel$ as hello.s -o hello.o ; ld -o hello hello.o ; ./hello
q
~/devel$
~/devel$

 
 
Last edited by a moderator:
Registers wear like NAND maybe ? ^^

So here's the compare char working code :

Code:
        .text
        .align 2

        .global _start

_start:
        ldr r8, =quit_char @ will load the address of quit_char into r8
        ldrb r8, [r8]      @ load a byte from memory (pointed to r8) to r8
        mov r2, #1    @ buffer length

_loop:
        mov r0, #0    @ file descriptor 0 - stdin
        mov r7, #3    @ system call number, 3 is 'read'
        ldr r1, =input @ will load the input into r1
        svc 0          @ call the Linux kernel and wait for the input
        ldrb r1, [r1] @ load a byte from memory (pointed to r1) to r1

        cmp r1, r8    @ compare if the input == q
        bne _loop     @ if not, come back to _loop

        mov r7, #1    @ exit
        svc 0

        .data
input:       .byte 0
quit_char:   .byte 'q'
 
Last edited by a moderator:
Registers are more like RAM than flash memory (although they're much faster to access than even L1 cache RAM).  Volatile memory doesn't have write count limits like flash, as far as I know (though presumably it does have some mtbf).  So you can't wear out a register just by using it.

Since you've moved the setting of r2 out of the loop, can you not also move where you set r7 out there too?  And maybe r1 too?  We know r0 gets used to return error conditions, so you'll need to reset that, but everything else?
 
Last edited by a moderator:
Was joking ^^.
R7 out the loop worked, but r1 too led to a segfault.

Here's the new char compare code :

Code:
        .text
        .align 2

        .global _start

_start:
        ldr r8, =quit_char @ will load the address of quit_char into r8
        ldrb r8, [r8]      @ load a byte from memory (pointed to r8) to r8
       	mov r2, #1    @ buffer length
        mov r7, #3    @ system call number, 3 is 'read'

_loop:
        mov r0, #0    @ file descriptor 0 - stdin
        ldr r1, =input @ will load the input into r1
        svc 0          @ call the Linux kernel and wait for the input
        ldrb r1, [r1] @ load a byte from memory (pointed to r1) to r1

        cmp r1, r8    @ compare if the input == q
        bne _loop     @ if not, come back to _loop

        mov r7, #1    @ exit
        svc 0

        .data
input:       .byte 0
quit_char:   .byte 'q'
 
 
R7 out the loop worked, but r1 too led to a segfault.

Probably because you are overwriting r1 in the first iteration.   If you were loading the contents of the memory r1 referred to into another register, instead of overwriting it,  then I reckon you could set r1 outside the loop.

-Neelix
 
R7 out the loop worked, but r1 too led to a segfault.

Probably because you are overwriting r1 in the first iteration.   If you were loading the contents of the memory r1 referred to into another register, instead of overwriting it,  then I reckon you could set r1 outside the loop.

-Neelix
You mean if you used for example "ldrb r0, [r1]" and "cmp r0, r8" :)
 
R7 out the loop worked, but r1 too led to a segfault.

Probably because you are overwriting r1 in the first iteration.   If you were loading the contents of the memory r1 referred to into another register, instead of overwriting it,  then I reckon you could set r1 outside the loop.
You mean if you used for example "ldrb r0, [r1]" and "cmp r0, r8" :)
Exactly! :)

-Neelix
 
Back
Top