I started to learn calling a function in assembly. I followed much tutorial in the internet and make some modification to it.
But it doesnot really work as expected.
.data
hello: .ascii "hello everyone\n"
len= . - hello
.text
.global _start
exit:
mov %r1,#0
mov %r2,#0
mov %r0, #0
mov %r7, #1
swi #0
println:
mov %r7, #4
swi #0
mov %pc, %lr
bx %r7
_start:
ldr %r1, =hello
ldr %r2, =len
b println
b exit
and the output goes
hello everyone
Segmentation fault
I dont know where i was wrong.
For function calls, use the bl (branch and link) instruction. This sets up lr to contain the return address. Your code uses b (branch) rather than bl, so lr is not set up and returning from println goes to an unpredictable address, likely crashing your program.
To fix this, use bl instead of b for function calls:
bl println
bl exit
Related
I am learning ARM assembly on my raspberry pi, and I am trying to write to a file called "user_data.txt". I do know how to create a file, like so...
.data
.balign 1
file_name: .asciz "user_data.txt"
.text
.global _start
_start:
MOV R7, #8
LDR R0, =file_name
MOV R1, #0777
SWI 0
_end:
MOV R7, #1
SWI #0
...but, as I said, I can't figure out how I would write to this file. I have looked at other tutorials, but none that I looked at explain what each line does. I understand that I would move 4 into R7, in order to call the sys_write system call, but how would I tell ARM the file name I want to write to?
Can anyone give some code which clearly shows and explains some ARM that writes to a file?
Thanks,
primecubed
So you wanted code:
.data
.balign 1
file_name: .asciz "user_data.txt"
.text
.global _start
_start:
MOV R7, #8
LDR R0, =file_name
MOV R1, #0777
SWI 0
MOV R7, #4 ;write(int fd, void* buf, int len)
LDR R1, =file_name ;buf
MOV R2, #9 ;len
SWI 0
MOV R7, #6 ;close(int fd)
SWI 0
_end:
MOV R7, #1
SWI #0
This will (for simplicity) write 9 chars of file_name (user_data) into the file and close it. Note that R0 always holds fd.
The manpages (https://linux.die.net/man/2/creat, https://linux.die.net/man/2/write) and this table (https://syscalls.w3challs.com/?arch=arm_thumb) are useful resources I often consult.
From a tutorial I got that movsb will copy data from ds:si to es:di. But in my case it's not working.
While try to debugging with gdb i cannot able to print values in s1 and s2 which decleared in .data section and .bss section respectively.
Any one please help how we can see value of s2 ,while printing $p2 i got void in debugging?
Why the value of s2 don't change with that of s1 here ?
code is given below
section .text
global _start
_start:
mov esi,s1
mov edi,s2
cld
rep movsb
mov edx,20
mov ecx,s2
mov ebx,1
mov eax,4
int 80h
mov eax,1
int 80h
section .data
s1 db 'qwerty',0
section .bss
s2 resb 20
When Linux starts your process, all your registers (including ECX) will be zero, except for ESP. (The ABI says they can hold garbage, but Linux chooses zero to avoid info leaks.)
Thus rep movsb will copy zero bytes. It's memcpy, not strcpy, it doesn't look at the data.
This is why your program doesn't just crash, like you'd expect from using rep movsb without setting ECX first.
I hope to use ARM to compile the function of my raspberry pie terminal: enter a number of Numbers, then make bubble sort in the program, and output the sorted result.
Compile and link no problem, but the screen appears "Illegal instruction" when executing the target file(ARM GNU style)
.globl _start
_start:
mov r4,#0
ldr r6,=src
add r6,r6,#len
outer:
ldr r1,=src
inner:
ldr r2,[r1]
ldr r3,[r1,#4]
cmp r2,r3
strgt r3,[r1]
Strgt r2,[r1,#4]
add r1,r1,#4
cmp r1,r6
blt inner
add r4,r4,#4
cmp r4,#len
suble r6,r6,#4
ble outer
stop:
mov r0,#0x18
ldr r1,=0x20026
swi 0x123456
.section .data
src:
.long 2,4,10,8,14,1,20
.equ len, 4
Now, I can use ARM assembler to implement bubble sort on my Raspberry pie without input character, the code is as follows:
.section .text
.global _start
_start:
mov r2,#10 #The number of characters output
mov r4,r2
b loop #Enter the first cycle
loop:
mov r1,pc #Point to the first position of the string
ldr r1,=str
sub r4,r4,#1
cmp r4,#0 #R4 is compared to 0, and if r4 is equal to 0,
#end up,print result
#greater than it goes into the second cycle
beq stop
mov r5,#0
b loop1 #The entrance to the second cycle
b loop
loop1:
ldrb r3,[r1] #R1 is pointing to the memory address of the value of
#the assignment to the r3 register
ldrb r6,[r1,#1]
cmp r3,r6 #r3 r6 compared
strgtb r3,[r1,#1] #If greater than r6, their values are exchanged
strgtb r6,[r1]
add r1,r1,#1 #R1 points to the next character
add r5,r5,#1
cmp r5,r4 #r5 r4 compared
bne loop1 #r5<r4 next loop1
b loop #r5=r4,Jump out of the second cycle and return to the
#first cycle
stop:
#printf str
add r2,r2,#1
mov r0,#0x1
mov r1,pc
ldr r1,=str
mov r7,#0x4
svc 1
#exit
mov r0,#0x0
mov r7,#0x1
svc 1
#Define data segment
.data
str:
.ascii "7543216890\n"
The result is:0123456789enter image description here
When I try to compile this ARM asm with as (arm-linux-gnueabihf):
.data
len = 42
.text
mov r0, #13
...it works. However, when I replace #13 with =len:
.data
len = 42
.text
mov r0, =len
I get:
Error: immediate expression requires a # prefix -- `mov r0,=len'
I've tried #len and #=len, neither seem to work. How do I refer to a named constants from the .data section in the .text section in ARM syntax?
Update:
Yeah, I had gotten section addresses and constants confused. For posterity, here is ARM hello world in unified syntax:
.syntax unified
.data
msg:
.ascii "Hello, ARM!\n"
len = . - msg
.text
.globl _start
_start:
mov r0, 1
ldr r1, =msg
mov r2, len
mov r7, 4
svc 0
mov r0, 0
mov r7, 1
svc 0
I am trying to print a number that I have stored. I'm not sure if I am close or way off. Any help would be appreciated though. Here is my code:
.data
.balign 4
a: .word 4
.text
.global main
main:
ldr r0, addr_of_a
mov r1, #8
str r1, [r0]
write:
mov r0, #1
ldr r1, addr_of_a
mov r2, #4
mov r7, #4
swi #0
bx lr
addr_of_a: .word a
It compiles and runs, but I don't see anything printed. From what I understand, I need the address of where to start printing in r1, how many bytes in r2, the file descriptor in r0, and r7 specifies the write call if it is set to #4. I am simply trying to store #8, then print the stored number.
The syscall write takes on the second argument (r1) as a pointer to the string you want to print. You are passing it a pointer to an integer, which is why it's not printing anything, because there are no ASCII characters on the memory region you are passing to it.
Below you'll find a "Hello World" program using the syscall write.
.text
.global main
main:
push {r7, lr}
mov r0, #1
ldr r1, =string
mov r2, #12
mov r7, #4
svc #0
pop {r7, pc}
.data
string: .asciz "Hello World\n"
If you want to print a number you can use the printf function from the C library. Like this:
.text
.global main
.extern printf
main:
push {ip, lr}
ldr r0, =string
mov r1, #1024
bl printf
pop {ip, pc}
.data
string: .asciz "The number is: %d\n"
Finally, if you want to print the number with the syscall write you can also implement a itoa function (one that converts an integer to a string).
Hi I appreciate that this is a pretty old thread but I've scratched my head over this for a while and would like to share my solution. Maybe it'll help someone along the way!
I was aiming to print to digit without recourse to using C++ in any way, though I realise that simply decompiling a tostring() - or whatever equivalent exists in C++ - and seeing what that came up with would have been a far quicker route.
Basically I ended up with creating a pointer to an empty .ascii string in the section .data and added the digit that I wanted to print + 48 to it before printing off that digit.
The +48 of course is to refer to the specific digit's ascii index number.
.global _start
_start:
MOV R8, #8
ADD R8, R8, #48
LDR R9, =num
STR R8, [R9]
MOV R0, #1
LDR R1, =num
MOV R2, #1
MOV R7, #4
SWI 0
.data
num:
.ascii: " "
The biggest drawback of this approach is that it doesn't handle any number more than one digit long of course.
My solution for that was much, much uglier and beyond the scope of this answer here but if you've a strong stomach you can see it here: