for, if in assembly language (bubble sort) - c

I made an bubble sort program in C, and checked its assembly listing file. But I cannot get where the for loops are. Could you let me know where are the for loops and if statement?
#include<stdio.h>
int main()
{
int arr[5]={2,4,5,6,1};
int i,j,tmp;
for(i=0;i<5;i++)
{
for(j=0;j<4;j++)
{
if(arr[j]>arr[j+1])
{
tmp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
}
}
}
for(i=0;i<5;i++){
printf(" %d",arr[i]);
}
printf("\n");
return 0;
}
And here is assembly listing file.
; generated by ARM C Compiler, ADS1.2 [Build 848]
; commandline [-O1 -browseinfo "0xff
" -S -g+ -fk -J:cw:]
CODE32
AREA ||.text||, CODE, READONLY
main PROC
|L1.0|
STMFD sp!,{r4,lr}
SUB sp,sp,#0x18
MOV r2,#0x14
LDR r1,|L1.148|
ADD r0,sp,#4
BL __rt_memcpy_w
MOV r12,#0
|L1.28|
MOV r0,#0
|L1.32|
ADD r1,sp,#4
ADD r2,sp,#4
ADD r3,r2,r0,LSL #2
LDR r1,[r1,r0,LSL #2]
LDR r2,[r3,#4]
CMP r1,r2
BLE |L1.72|
ADD lr,sp,#4
STR r2,[lr,r0,LSL #2]
STR r1,[r3,#4]
|L1.72|
ADD r0,r0,#1
CMP r0,#4
BLT |L1.32|
ADD r12,r12,#1
CMP r12,#5
BLT |L1.28|
MOV r4,#0
|L1.100|
ADD r0,sp,#4
LDR r1,[r0,r4,LSL #2]
ADR r0,|L1.152|
BL _printf
ADD r4,r4,#1
CMP r4,#5
BLT |L1.100|
ADR r0,|L1.160|
BL _printf
MOV r0,#0
ADD sp,sp,#0x18
LDMFD sp!,{r4,pc}
|L1.148|
DCD ||.constdata$1||
|L1.152|
DCB " %d"
DCB "\0\0\0\0"
|L1.160|
DCB "\n\0\0\0"
ENDP
AREA ||.constdata||, DATA, READONLY, ALIGN=2
||.constdata$1||
DCD 0x00000002
DCD 0x00000004
DCD 0x00000005
DCD 0x00000006
DCD 0x00000001
EXPORT main
IMPORT _main
IMPORT __main
IMPORT _printf
IMPORT __rt_memcpy_w
IMPORT ||Lib$$Request$$armlib||, WEAK
KEEP

Here you go. If you just looked for CMP and the constants, you should have been able to find them:
LDR r1,[r1,r0,LSL #2] ; r1 = arr[j]
LDR r2,[r3,#4] ; r2 = arr[j+1]
CMP r1,r2 ; arr[j] <= arr[j+1]
BLE |L1.72| ; jump if yes
ADD lr,sp,#4 ; arr
STR r2,[lr,r0,LSL #2] ; arr[j] = arr[j+1]
STR r1,[r3,#4] ; arr[j+1] = arr[j]
|L1.72|
ADD r0,r0,#1 ; j++
CMP r0,#4 ; j < 4
BLT |L1.32| ; jump to inner loop if yes
ADD r12,r12,#1 ; i++
CMP r12,#5 ; i < 5
BLT |L1.28| ; jump to outer loop if yes

Related

Instruction would span across PC

I use arm-gcc to compile the code for cortext-m4, but the code will crash when enter the function
char buf[20];
sprintf(buf, "%d",1);
I use lauterbach Trace32 to debug the code, before enter the "sprintf" function it is:
E92D000E siprintf: push {r1-r3}
E3E03102 mvn r3,#-0x80000000 ; r3,#-2147483648
E52DE004 push {r14}
E24DD070 sub r13,r13,#0x70 ; r13,r13,#112
E58D0008 str r0,[r13,#0x8]
E58D0018 str r0,[r13,#0x18]
E58D301C str r3,[r13,#0x1C]
E58D3010 str r3,[r13,#0x10]
E59F0038 ldr r0,0xE628
E59F3038 ldr r3,0xE62C
E59D2074 ldr r2,[r13,#0x74]
E58D3014 str r3,[r13,#0x14]
E28D1008 add r1,r13,#0x8 ; r1,r13,#8
E28D3078 add r3,r13,#0x78 ; r3,r13,#120
E5900000 ldr r0,[r0]
E58D3004 str r3,[r13,#0x4]
EB0000B2 bl 0xE8D8 ; _svfiprintf_r
E3A02000 mov r2,#0x0 ; r2,#0
E59D3008 ldr r3,[r13,#0x8]
but when it enter the function it change to:
000E siprintf: //////// ; **instruction would span across PC**
E92D align 0xE92D
E3E03102 mvn r3,#-0x80000000 ; r3,#-2147483648
E52DE004 push {r14}
E24DD070 sub r13,r13,#0x70 ; r13,r13,#112
E58D0008 str r0,[r13,#0x8]
E58D0018 str r0,[r13,#0x18]
E58D301C str r3,[r13,#0x1C]
E58D3010 str r3,[r13,#0x10]
E59F0038 ldr r0,0xE628
E59F3038 ldr r3,0xE62C
E59D2074 ldr r2,[r13,#0x74]
E58D3014 str r3,[r13,#0x14]
E28D1008 add r1,r13,#0x8 ; r1,r13,#8
E28D3078 add r3,r13,#0x78 ; r3,r13,#120
E5900000 ldr r0,[r0]
E58D3004 str r3,[r13,#0x4]
EB0000B2 bl 0xE8D8 ; _svfiprintf_r
E3A02000 mov r2,#0x0 ; r2,#0
E59D3008 ldr r3,[r13,#0x8]
which complier option or link option I should use to avoid this problem?

C nested loop to ARM assembly

I'm currently having issues translating a C program to ARM assembly. The C program is as follows:
int i = 1;
int j = 0;
int x = 0;
int main(){
for( ; i < 10; i += 2){
for( j = i; j < 10; j++){
x += i + j;
}
}
return x;
}
This code will output 240.
What I have currently is as follows:
.data
i: .word 1
j: .word 0
x: .word 0
.text
.global main
main:
LDR r6, addrJ
LDR r5, addrI
LDR r4, addrX
LDR r3, [r6]
LDR r2, [r5]
LDR r1, [r4]
b loop_outer
loop_outer:
CMP r2, #10
BGE done
MOV r3, r2 # j = i
loop_inner:
CMP r3, #10 # j < 10
BGE inner_done
ADD r1, r1, r2 # x+=i
ADD r1, r1, r3 # x+=j
ADD r3, r3, #1 # j++
inner_done:
ADD r2, r2, #2 # i+=2
b loop_outer
b done
done:
MOV r0, r1
bx lr
addrI: .word i
addrX: .word x
addrJ: .word j
This code currently outputs 50. I have tried debugging myself but I have been having a hard time with GDB.
You're missing the b loop_inner to repeat the inner loop.
And b done is not needed, since it's after the unconditional b loop_outer, so it will never be executed.
loop_outer:
CMP r2, #10
BGE done
MOV r3, r2 # j = i
loop_inner:
CMP r3, #10 # j < 10
BGE inner_done
ADD r1, r1, r2 # x+=i
ADD r1, r1, r3 # x+=j
ADD r3, r3, #1 # j++
b loop_inner
inner_done:
ADD r2, r2, #2 # i+=2
b loop_outer
done:
MOV r0, r1
bx lr

In Assembly how would I get the value from a call function?

This my C code for my MSP430. I am trying to write str = word_start(str); in assembly but I am not sure if this is correct.
char** tokenize(char* str){
int totalWords = count_words(str);
printf("%d\n", totalWords);
char **array;
array = (char **)malloc(sizeof(char*) * (++totalWords));
//filling the array with individual words
int diff = 0;
int i;
for(i = 0; i < totalWords-1; i++){
str = word_start(str);
// find difference in length
diff = word_terminator(str) - str;
// add new allocated string to array
array[i] = copy_str(str, diff);
// update pointer p to next word
str = word_terminator(str);
}
array[i] = '\0';
return array;
}
This is my assembly code, I want to convert the above method from C to MSP430 assembly.
tokenize:
mov r12, 0(r1) ; put str in str
call #count_words
mov r12 2(r1) ;
mov 2(r1), r12 ; get totalWords
add #1, r12 totalword
add r12, r12
call #malloc
mov r12 4(r1)
mov #0 6(r1) ; int i = 0;
mov #0 8(r1) ; int diff = 0;
top: cmp 0(r1), 6(r1)
JL end
mov 0(r1), r12
call #word_start ; calling word start
mov r12, 0(r1) ; getting the value returned
mov 0(r1), r12
call #word_terminator
mov r12, 8(r1)
mov 0(r1), r12
mov 8(r1), r13
sub r12, r13
call #copy_str
mov r12, 10(r1) ; what we get from cpoy_str put in r12
mov 6(r1), r12 ; put I in r12
add r12, r12 ; add r12
add 4(r1), r12 ; add 4(r1) to whats in r12
mov 10(r1), #r12 ; put what we r12 is in 10(r1)
mov 0(r1), r12
call #word_terminator
move r12, 0(r1)
mov 0(r1), r12
add #1, 6(r1) ; increment i
end:
mov 6(r1), r12
add r12, r12
add 4(r1), r12
mov #0, #r12,
add #12, r1
ret
When I call word_start in assembly, is the way I am passing the value str and getting the value returned done correctly? If not can you show me how you're supposed to pass in variables in assembly to a function and get the returned value from that function?

Execution does not go out of the loop in ARM

I want to print in ARM assembly language a given number in decimal in hexadecimal. I'm doing the function that does the conversion and the printing. So far the conversion works but the printing not at all.
It does only print a char at a time and it's not at all what I want, I want a special format of output such that I have 0x and 8 digits.
I wrote a function printf using the given function I had, called _writec that is working but only printing a char at a time. So I wrote a loop until I get the end of string function but here it seems that it doesn't care.
I've followed the execution step-by-step using gdb and it suddenly crash for no appearing reason. When r0 contain 0 it should go to .end according to my beq but it does not.
ARM Code:
.global _print_hex
_print_hex:
push {lr}
#According to .c algorithm : r0 = dec; r1 = quotient;
# r2 = temp; r3 = i ; r4 = j
mov fp, sp
sub sp, sp, #100 # 100 times size of char
mov r1, r0
mov r3, #0
_while:
cmp r1, #0
bne _computing
ldr r0, =.hex_0x
bl _printf
mov r4, #8
_for:
cmp r4, #0
bge _printing
ldr r0, =.endline
bl _printf
mov sp, fp
pop {pc}
_computing:
and r2, r1, #0xF
cmp r2, #10
blt .temp_less_10
add r2, #7
.temp_less_10:
add r2, #48
strb r2, [sp, r3]
add r3, #1
lsr r1, #4
b _while
_printing:
ldrb r0, [sp,r4]
bl _writec
sub r4, #1
b _for
_printf:
push {r0, r1, r2, r3, lr}
mov r1, r0
mov r2, #0
.loop:
ldrb r0, [r1,r2]
cmp r0, #0
beq .end
bl _writec
add r2, #1
b .loop
.end:
pop {r0, r1, r2, r3, lr}
bx lr
.hex_0x:
.asciz "0x"
.align 4
.endline:
.asciz "\n"
.align 4
C code (that I tried to translate):
void dec_to_hex(int dec){
int quotient, i, temp;
char hex[100];
quotient = dec;
i = 0;
while (quotient != 0){
temp = quotient % 16;
if (temp < 10){
temp += 48; // it goes in the ascii table between 48 and 57 that correspond to [0..9]
} else {
temp += 55; //it goes in the first cap letters from 65 to 70 [A..F]
}
hex[i]=(char)temp;
i++;
quotient /= 16;
}
printf("0x");
for(int j=i; j>=0; j--){
printf("%c", hex[j]);
}
printf("\n");
}
Here is the code of _writec :
/*
* Sends a character to the terminal through UART0
* The character is given in r0.
* IF the TX FIFO is full, this function awaits
* until there is room to send the given character.
*/
.align 2
.global _writec
.type _writec,%function
.func _writec,_writec
_writec:
push {r0,r1,r2,r3,lr}
mov r1, r0
mov r3, #1
lsl r3, #5 // TXFF = (1<<5)
ldr r0,[pc]
b .TXWAIT
.word UART0
.TXWAIT:
ldr r2, [r0,#0x18] // flags at offset 0x18
and r2, r2, r3 // TX FIFO Full set, so wait
cmp r2,#0
bne .TXWAIT
strb r1, [r0,#0x00] // TX at offset 0x00
pop {r0,r1,r2,r3,pc}
.size _writec, .-_writec
.endfunc
So in ARM when debugging it crashed at my first call of _printf and when I comment all the call to _printf it does print the result but not as the desired format. I only got the hex value.

Recursive Insertion Sort in Assembly

I am trying to implement insertion sort in Assembly ARMV-8A. More specifically i tried to translate the following code in C:
void insertionSortRecursive(int arr[], int n)
{
   
    if (n <= 1)
        return;
 
    insertionSortRecursive( arr, n-1 );
    int last = arr[n-1];
    int j = n-2;
 
    while (j >= 0 && arr[j] > last)
    {
        arr[j+1] = arr[j];
        j--;
    }
    arr[j+1] = last;
}
 
I have tried to translate it as it is but my implementation gets into infinite loop in function loop_insertion as debugger shows:
.data
my_Table: .space 16
size: .word 4
FileOpenMode: .string "r"
FileName: .string "test1.txt"
fscanf_str: .string "%d"
printf_str: .string "%d "
out_message_str: .string "%d "
.text
.global main
main:
stp x29,x30,[sp,-32]!
add x29,sp,0
adr x1,FileOpenMode
adr x0,FileName
bl fopen
mov x20,x0
adr x0,my_Table
mov x22,x0 //x22 adr of table
mov x21,4
mov x23,0
//**************** READ FROM FILE ******************
loop:
add x2,x29,28
adr x1,fscanf_str
mov x0,x20
bl fscanf
ldr w1,[x29,28]
mov x0,x22
str w1,[x0,x23]
add x23,x23,4
add w21,w21,-1
cbnz w21,loop
//********************************************
mov x0,x22 //adr of table
mov x1,4
bl insertion_sort
//**************** PRINT TO SCREEN FROM TABLE *****************
mov x21,0
mov x23,4
loop_print:
adr x0, out_message_str
ldr w1,[x22,x21]
bl printf
add x21,x21,4
sub x23,x23,1
cbnz x23,loop_print
//***********************************************************
ldp x29, x30, [sp], 32
ret
insertion_sort:
stp x29,x30,[sp,-64]!
add x29,sp,0
str x19,[x29,32] //str the save register
str x0,[x29,16] //str the address of table
str w1,[x29,24] //str the n
mov x19,4
cmp w1,1
b.le exit_ins
sub w1,w1,1
bl insertion_sort
ldr w9,[x29,24] //load the n for the suitable function
sub w9,w9,1 //n-1
mul w9,w9,w19
ldr x10,[x29,16] //adr table
ldr w11,[x10,x9] //last
udiv w9,w9,w19
sub w12,w9,1 //j=n-2
loop_insertion:
ldr w12,[x29,24]
cmp w12,0
b.lt label1
mul w12,w12,w19
ldr w13,[x10,x12] // w13=arr[j]
cmp w13,w11
b.le label1
add w12,w12,w19
str w13,[x10,x12] //arr[j+1]=w13
udiv w12,w12,w19
sub w12,w12,1
str w12,[x29,24]
b loop_insertion
label1:
add w12,w12,1
mul w12,w12,w19
str w11,[x10,x12]
exit_ins:
ldr x19,[x29,32] //ldr the value of x19 back to the x19
ldp x29, x30, [sp], 64
ret
I did some modifications such as loading and storing the value of n-2 inside the insertion_loop function but that does not make any change.
You need to comment your code better, especially if you want others to help.
I am guessing that instead of preserving j in w12 you are doing calculations with it and then try to get the original value back but fail. Since you have done add w12,w12,w19 to get arr[j+1], the value of w12 after udiv w12,w12,w19 will be j+1 and when you subtract one from that you end up with j again, hence the infinite loop. You have tons of registers, just use a different one for the j+1.
You should have been able to see this in your debugger.

Resources