Can't get newline to print with ARM Linux assembly - linux

I started with code from a Raspberry Pi assembly language book. It prints out 15 in binary as so:
00000000000000000000000000001111pi#raspberrypi:$
I wanted to add a newline at the end, so I implemented the _newline: and new: .ascii "\n" portion of the code.
I reassembled it, but the output remains the same. Did I miss something in outputting the newline?
.global _start
_start:
mov r6, #15
mov r10, #1
mov r9, r10, lsl #31
ldr r1, =string
_bits:
tst r6, r9
moveq r0, #48
movne r0, #49
str r0, [r1]
mov r8, r6
bl _write
mov r6, r8
movs r9, r9, lsr #1
bne _bits
_newline:
mov r0, #1
mov r2, #1
mov r7, #4
ldr r1, =new
swi 0
_exit:
mov r7, #1
swi 0
_write:
mov r0, #1
mov r2, #1
mov r7, #4
swi 0
bx lr
.data
string: .ascii " "
new: .ascii "\n"
The last few lines of strace output are:
write(1, "1", 11) = 1
write(1, "1", 11) = 1
write(1, "1", 11) = 1
write(1, "1", 11) = 1
write(1, "\0", 11) = 1
exit(1) =?
+++ exited with 1 +++

Your strace output is the clue: write(1, "\0", 11) = 1 shows us that you wrote a 0 byte instead of the ASCII encoding of \n.
When you str r0, [r1], you're storing 4 bytes.
The destination of that store is
.data
string: .ascii " "
new: .ascii "\n"
which is really:
.data
string: .byte ' '
new: .byte '\n'
So each time you store '0' or '1' to string, you're also writing 3 more zero bytes, clobbering your '\n' and 2 more bytes beyond the end of your data section. (It doesn't segfault because you're not right at the end of a page.)
The simplest fix is to use a single-byte store: strb r0, [r1] instead of the word-sized str.

Related

Armv7 Assembly - Extra console prompt "pi#raspberrypi:~ $ " when I press enter?

I get this output from my program which takes a user input, and replaces the linefeed with a null terminating and prints it back out to the console
pi#raspberrypi:~ $ ./tester
Please enter 4 different numbers between 1-5 together without space or special characters.
1234
1234
pi#raspberrypi:~ $
pi#raspberrypi:~ $
But when I type 123 I only get a single line prompt which is what I'm looking for when I enter 1234.
pi#raspberrypi:~ $ ./tester
Please enter 4 different numbers between 1-5 together without space or special characters.
123
123
pi#raspberrypi:~ $
This is the code I'm executing, it's as minimum as I could get it for minimum functional requirements.
.global _start
_start:
LDR r1, =prompt
BL _sPrint
LDR r1, =userInput # point to the space allocated for input
MOV r2, #4 # set the limit of character to read in
BL _sInput
LDR r1, =userInput
BL _sPrint
Ldr r1, =newline
BL _sPrint
B _exit
#_sPrint prints out a string based on it's variable length determined by _strlen
#strlen, and findEnd are both needed for _sPrint.
_sPrint:
MOV r7, #4 #sets r7 to console STDOUT
MOV r0, #1 #set WRITE destination to STDOUT (terminal)
PUSH {r0, r1, lr}
BL _strLen #gets the stringlength and the end
POP {r0, r1, lr}
SWI 0
mov pc, lr
_strLen:
mov r2, #0
#find end of strlen finds the end of the string and stores the length in r2 for console output
findEnd:
LDRB r0, [r1], #1
ADD r2, r2, #1
CMP r0, #0
BNE findEnd
SUB r2, r2, #1
MOV pc, lr
_sInput:
PUSH {R1-R8, lr}
MOV r7, #3 #register r7 being set to 3 to indicate message being read in (read syscall)
MOV r0, #0 #Set READ device to the STDIN (keyboard)
SWI 0
POP {R1-R8, lr}
#String fix takes a string value at r1's address and changes the line feed to be null termianted.
strfx:
LDRB r0, [r1],#1 #loads a single byte from r1 (r1 is dereferenced), which is the _sInput to r0
CMP r0, #10 #is r0 our newline?
BNE strfx
MOV r0, #0 #set r0 to null
STRB r0, [r1, #-1] #store r0's value back into r1's current address location. The final address
MOV PC, LR #location of r1 newline to be the NULL in r1.
_exit:
MOV r7, #1
SWI #0
.data
prompt: .asciz "\nPlease enter 4 different numbers between 1-5 together without space or special characters. \n \n"
newline: .asciz "\n"
userInput: .space 6
You're reading four characters. When the user enters "1234\n" (five characters), the newline is left in the input buffer to be read by the shell. When the user enters "123\n", the newline is actually read by you. Since you have newline-handling code, the solution is simple: you need to read five characters, not four.

ARM Assembly loading string produces weird terminal output

I am trying to space out my string by replacing each character with a space string combined with an underscore string to create _ _ _ _.
However, I get a weird output:
If I load 1 character e.g ldr r1, = '_'
it works however I get _____ and I am trying to get _ _ _ _ _. What is the best way to do this?
NOTE: I do not know C and I am new to ARM.
My function:
sub r3, r0, #1 #has the length
ldr r0, = buffer #has the word
mov r5, #0 #start of increment
mov r6, r0 #copies word to r6
loop:
ldr r1, =spaceChar
strb r1, [r6, r5]
add r5, r5, #1
cmp r3, r5
bne loop
mov r1,r6
ldr r0, = HiddenWord
bl printf
pop {r4,lr}
bx lr
.data
HiddenWord:
.asciz "Word: %s"
spaceChar:
.asciz " _"
buffer:
.space 100
Since you already statically allocate the buffer the simplest solution is to preset it with " _" using your assembler and just put the terminating zero in the right place. I don't think you mentioned which assembler you use, the following works in gnu assembler:
ldr r0, =buffer-1
mov r1, #0
strb r1, [r0, r3, lsl #1]
ldr r0, =HiddenWord
ldr r1, =buffer
bl printf
pop {r4,lr}
bx lr
.data
HiddenWord:
.asciz "Word: %s\n"
buffer:
.rept 50
.ascii "_ "
.endr
If you want to fill the buffer programmatically, that could look like:
ldr r0, =buffer #has the word
ldr r1, =0x205f # underscore + space
loop:
strh r1, [r0], #2
subs r3, r3, #1
bne loop
mov r1, #0 # replace final
strb r1, [r0, #-1] # space with zero

How do I write to files in ARM assembly?

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.

Print Newline for Armv7 assembly program

I'm working on this armv7 assembly program that finds the greatest common divisor(gcd) of two integers. Everything is working fine except for the newline function. When i assemble and run the program, it doesn't print any newlines, just the integers in one line. Any suggestions on how i can fix that?
.global _start
_start:
mov r2, #24 #first set of integers
mov r4, #18
bl mysub1
bl mysub2
bl mysub3
mov r2, #78 #second set of integers
mov r4, #34
bl mysub1
bl mysub2
bl mysub3
mov r2, #99 #third set of integers
mov r4, #36
bl mysub1
bl mysub2
bl mysub3
_exit:
mov r7, #1
swi 0
mysub1: #subroutine to find gcd
cmp r2, r4
beq done
bgt greater
blt less
greater:
sub r2, r2, r4
bal mysub1
less:
sub r4, r4, r2
bal mysub1
done:
bx lr
mysub2: #subroutine to convert gcd result to ascii value
add r4, #48
ldr r9, =store
str r4, [r9]
mov r7, #4 #print out a newline
mov r0, #1
mov r2, #1
ldr r1, =newline
swi 0
bx lr
mysub3: #subroutine to print out the ascii value
mov r7, #4
mov r0, #1
mov r2, #2
ldr r1, =store
swi 0
bx lr
.data
store:
.space 2
newline:
.ascii "\n"
This is the culprint:
add r4, #48
ldr r9, =store
str r4, [r9]
This code has two bugs:
it only works for numbers between 0 and 9
str r4, [r9] stores four bytes to store, overwriting the newline right after the two-byte buffer.
To fix the first issue, you need to do a division with rest to separate the number in r4 into two digits. To fix the second issue, use strb or strh to store a byte or halfword instead as to not overrun the buffer.

Getting a segfault when I want to return string length in ARM assembler on a raspberry

So I'm a beginner in ARM assembler.
I'm trying to return the length of "Hello, World!", so it must be 13. Here is my source code:
.section .rodata
.align 2
message:
.string "Hello, world!"
afficher:
.string "%d"
.text
.align 2
.global main
long:
stmfd sp!, {lr}
ldrb r2, [r0]
cmp r2, #0
beq out
add r1,r1,#1
add r0,r0, #1
bl long
ldmfd sp!, {lr}
bx lr
.global main
main:
stmfd sp!, {lr}
ldr r0, =message
mov r1, #0
bl long
ldmfd sp!, {lr}
bx lr
out :
ldr r6, =message
bl printf
mov r0, r1
ldr r3, =afficher
mov r4, r1
mov r5, r0
bl printf
.global main
I don't know where is the problem honestly. Can anyone help me please?! thanx
So, after some further looking up into my code, here is a working code:
.section .rodata
.align 2
message:
.string "Hello, world!"
print:
.string "Length is : %d\n"
.text
.align 2
.global main
strlen:
stmfd sp!, {lr}
ldrb r2, [r0]
cmp r2, #0
beq out
add r1, r1, #1
add r0, r0, #1
bl strlen
ldmfd sp!, {lr}
bx lr
.global main
main:
stmfd sp!, {lr}
ldr r0, =message
mov r1, #0
bl strlen
ldmfd sp!, {lr}
bx lr
out:
stmfd sp!, {lr}
ldr r0, =print
mov r3, r1
bl printf
ldmfd sp!, {lr}
bx lr
At first, I was giving a "Hello, world!\n" string to calculate the length, for that it returned 14, but without the "\n" it return 13.
Thanks for your help every one , and I would welcome any other remarques on this code if you still have any!

Resources