Implement bubble sort by ARM assembly - io

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

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.

moving from memory to register and reading it in gdb

section .data
price dd 49,98,29
section .text
global _start
_start:
nop
; Put your experiments between the two nops...
mov eax,price
mov ebx,[price]
mov ecx,[price+4]
mov edx, [price+8]
; Put your experiments between the two nops...
nop
I understand that 49,98,29 are a byte apart from. When price is referenced it will only print out 49. I must move price by 1 byte to get 98 and 2 bytes to get 29.
In gdb I can see that the register edx has the decimal 29, ecx 98 and ebx 49.
However when I examine the register with x/3dw $edx I get
Cannot access memory at address 0x1d
Why isn't it showing 29?
Update:
I am trying to see output of the code below
section .data
price db 49,98,29
section .text
global _start
_start:
nop
; Put your experiments between the two nops...
mov eax, price
mov ebx,[price]
mov ecx,[price+1]
mov edx, [price+2]
; Put your experiments between the two nops...
nop
x/db $ebx gives
0x1d6231: Cannot access memory at address 0x1d6231
and
(gdb) p $ebx
$5 = 1925681
Why is it doing this?

SegFault when calling function in asm

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

Loop Segmentation Fault

This is my code so far.
.data
S: .string "-149"
Length: .byte -1
Result: .quad
.text
.globl main
main:
mov S,%rdx #Storage of string, counter, position and result in memory
mov Length, %rcx
mov Result, %rax
mov $10, %r10
mov $30, %r13
mov $-1, %r9
Loop1: #loop string from beginning to end
cmp $0,0(%rdx) #compare base addresss value with null
je Counter_Made #if null, branch to end loop.
add %r14, Length #increment length by for each digit thats not null (creates counter for 2nd loop)
add $1, %rdx #increment base by 1 to move onto next digit in string
jmp Loop1 #reinitiate loop
Counter_Made:
cmp %r15,Length #check if length is zero
je Output #End program, output null result
cmp %r15,Length(%rdx) #Determine negativity/positivity of integer
jl Negative_counter
jmp Positive_loop
Positive_loop:
cmp %r9,Length #End of loop check
je Output #Store result if loop end condition satisfied
mov %r10, Length(%rdx) #Store byte of integer in supplementary register
sub %r13, %r10 #Conversion from 8bitASCII to 2Bit Binary
imul %r11, %r10 #Place holder multiplication
add %r10, %rax #Store cumulative addition in memory
sub %r14, Length #Length decrement
jmp Positive_loop #reloop
Negative_counter:
sub %r14,Length
jmp Negative_loop
Negative_loop:
cmp %r9,Length
je Negative_Complement
mov %r10, Length(%rdx) #Store byte of integer in supplementary register
sub %r13, %r10 #Conversion from 8bitASCII to 2Bit Binary
imul %r10, %r10 #Place holder multiplication
add 0(%rdx), %rax #Store cumulative addition in memory
sub %r14, Length
jmp Negative_loop
Negative_Complement:
not %rdx #Convert to 2's complement with negation and then + 1
add %r14,%rdx
jmp Output
Output:
mov %rdx, Result
ret
#size mismatch for imul
#Specific place in memory to put output or no?
The code is supposed to convert a character string that represents any signed integer to its 2’s complement value.
I'm receiving a segmentation fault in one of my loops and I've tried multiple different methods here but to no avail - could anyone explain how I should about fixing this segfault? I'm stumped.
Here is the GDB errors
Program received signal SIGSEGV, Segmentation fault.
Loop1 () at data.s:18
18 cmp $0,0(%rdx) #compare base addresss value with null
This is the second error.
Counter_Made () at data.s:28
28 cmp $0,Length(%rdx) #Determine negativity/positivity of integer, if <0 value is negative
I'm suspecting its the Length(%rdx) method that I'm trying to interpret the loop with. Would it be better to sub $1,%rdx
You want
mov $S,%edx
to load the address of the string into %rdx. This works because the program image is always loaded into the lower 4 GB of the address space. Alternatively, you can use a %rip relative lea to load the address even if the process image is loaded outside of the first 4 GB:
lea S(%rip),%rdx
but that instruction has a somewhat longer encoding (two extra bytes).
The instruction
mov S,%rdx
loads the first eight bytes of the memory S points to into %rdx, which is not what you want.

How to print a number in ARM assembly?

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:

Resources