Arm Assembly reversing a list in place - arm

I'm struggling to see where I'm going wrong in a function that reverses a list in place. The function takes a pointer of an array of long ints as x0 and a long int for the size of the array as x1.
When the code runs the first half of the list is correct but after the halfway point it mirrors the beginning. For example for the list [48, 307, 12, -18, -805] mine returns [-805, -18, 12, -18, -805].
So that makes me believe it stops reversing after it hits halfway. I'm not sure why it would do this and any help as to why it's doing this would be really appreciated. Thanks in advance!
.global reverse
.global loop
.global done
reverse:
cmp x1, #0 // if list is empty
beq empty // return 0
mov x3, x0 // copy of list
mov x2, x1 // size
sub x2, x2, #1 // size-1
lsl x2, x2, #3 // (size-1) * 8
add x3, x3, x2 // &data[size-1]
loop:
cmp x1, #0 // if we have reached the end of the list
beq done // return the reversed list
ldr x2, [x3] // get the reverse
str x2, [x0] //set x0 with the reverse
add x0, x0, #8 // x0++
sub x3, x3, #8 // x3--
sub x1, x1, #1 // length -1
b loop //loop
empty:
mov x0, #0
ret
done:
ret

Related

Inlined ARM64 system call giving the wrong return value

This is my code.
long doSystemCall(const char *path) {
register long x0 asm("x0") = 0;
register long x1 asm("x1") = (long) path;
register long x2 asm("x2") = 0;
register long x3 asm("x3") = 0;
register long x8 asm("x8") = __NR_faccessat;
__asm__ volatile("svc #0"
:"=r"(x0)
:"0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8)
:"memory"
);
__android_log_print(ANDROID_LOG_INFO, "SYSCALL", "Result: %li", x0);
return x0;
}
The return values it gives are 0, -2 or -13, however faccessat should only return 0 or -1. How can I fix this?
The decompiled pseudocode of my code looks like this.
signed __int64 __fastcall sub_E558(const char *a1)
{
signed __int64 v1; // ST30_8
v1 = linux_eabi_syscall(__NR_faccessat, 0, a1, 0, 0);
__android_log_print(4LL, "SYSCALL", "Result: %li", v1);
return v1;
}
And these are the instructions of the function.
SUB SP, SP, #0x50
STP X29, X30, [SP,#0x40+var_s0]
ADD X29, SP, #0x40
STUR X0, [X29,#var_8]
MOV X0, XZR
STUR X0, [X29,#var_10]
LDUR X8, [X29,#var_8]
STUR X8, [X29,#var_18]
STR X0, [SP,#0x40+var_20]
STR X0, [SP,#0x40+var_28]
MOV W9, #0x30
MOV W8, W9
STR X8, [SP,#0x40+var_30]
LDUR X0, [X29,#var_10]
LDUR X1, [X29,#var_18]
LDR X2, [SP,#0x40+var_20]
LDR X3, [SP,#0x40+var_28]
LDR X8, [SP,#0x40+var_30]
SVC 0
STUR X0, [X29,#var_10]
LDUR X3, [X29,#var_10]
ADRP X1, #aSyscall#PAGE ; "SYSCALL"
ADD X1, X1, #aSyscall#PAGEOFF ; "SYSCALL"
ADRP X2, #aResultLi#PAGE ; "Result: %li"
ADD X2, X2, #aResultLi#PAGEOFF ; "Result: %li"
MOV W0, #4
BL .__android_log_print
LDUR X8, [X29,#var_10]
STR W0, [SP,#0x40+var_34]
MOV X0, X8
LDP X29, X30, [SP,#0x40+var_s0]
ADD SP, SP, #0x50
RET
You're confusing the libc wrapper API with the direct syscall ABI -- only the libc wrapper returns errors in errno. The direct system call will return a small neagtive value (with the error code), at least on Linux. The libc wrapper will test the return value, and if it is the range -4096..-1, will negate it and store it in errno (and then return -1). Other UNIX variants (BSD) return the error indication in a flag (usually carry flag) with the error value in the return register.

Bus error in ARMv7 assembly function to find maximum element of array

I'm having trouble with an ARMv7 assembly function I'm trying to write. The function is below.
.global maxF32
// float maxF32(const float x[], uint32_t count)
// returns the maximum value in the array (x) containing count entries
/* R0 = float x[], R1 = uint32_t count */
maxF32:
CMP R1, #0 # SET FLAGS OF COUNT
BEQ maxF32_end # IF COUNT == 0, GO TO END
MOV R2, R0 # COPY R0 INTO R2
MOV R0, #0 # ZERO OUT R0
MOV R3, #0 # ZERO OUT R3
MOV S0, R0 # ZERO OUT S0
MOV S1, R0 # ZERO OUT S1
MOV S2, R0 # ZERO OUT S2
B maxF32_loop # BRANCH TO LOOP
maxF32_loop:
CMP R1, #0 # CHECK IF COUNT == 0
BEQ maxF32_end # IF SO, GO TO END
VLDR.F32 S0, [R2] # LOAD CURRENT ELEMENT INTO S0
ADD R2, R2, #4 # INCREMENT VECTOR POINTER
VLDR.F32 S1, [R2] # LOAD NEXT ELEMENT INTO S1
SUB R1, R1, #1 # DECREMENT COUNT
CMP S0, S1 # SET FLAGS; CHECK S0 - S1
BMI maxF32_update # IF RESULT IS NEGATIVE (S1 > S0), GO TO UPDATE GREATEST
B maxF32_loop # REPEAT LOOP
maxF32_update:
VMOV R3, R1, S1 # MOVE GREATER INTO GREATEST REGISTER
B maxF32_loop # GO BACK TO LOOP
maxF32_end:
MOV R0, R3 # COPY GREATEST INTO R0
BX LR # RETURN
I test with the following C code:
extern float maxF32(const float x[], uint32_t count);
#define COUNT 3
float x[] = {1.2, 1.3, 1.4};
float result;
result = maxF32(x, COUNT);
printf("result is %lf\n", result);
Using gdb, right around the second to last or last loop through the array, I get a "bus error" right around the CMP S0, S1 line. I sometimes also get an "expected comma" at MOV R3, R1, S1, which confuses me as I don't know where I would need an extra comma.
Last note, I am coding on a Raspberry Pi Model 3 B+.
Thanks for any and all help.
On a count of "3" you compare s0 to s1 3 times.... meaning you look for four elements in the array. (With n elements you really should only have n-1 comparisons)
The logic...
decrement count
cmp element0 element1 ... loop
decrement count
compare element1 element2 ... loop
decrement count
compare element2 with 'bus error' -- nothing there.
Moving SUB R1, R1, #1 to the first line after maxF32_loop: probably fixes it as it puts the decrement before the check for count being 0.

Getting incorrect returned values from assembly to C [duplicate]

This question already has answers here:
What are callee and caller saved registers?
(6 answers)
ARM assembly - access parameter vs return value?
(2 answers)
ARM64 using gas on iOS?
(2 answers)
Closed 3 years ago.
I am calling push and pop (from my assembly code) in C like so:
int main()
{
push(8);
push(1);
push(pop() + pop());
return 0;
}
But I don't get the correct values when I do push(pop() + pop()). When debugging in gdb for push I get
=> 0x4008a8 <main+420>: add w0, w19, w0
(gdb) p $w0
$16 = 8
(gdb) p $w19
$17 = 4325452
As you can see, w0 gives me the correct value of 8 but w19 gives me 4325452 when it should be 1. Probably because my first returned pop value isn't saved in main.
Here are my push and pop subroutines in assembly:
push: stp x29, x30, [sp, -16]!
mov x29, sp
mov w9, w0 // 1st operand: int f (input)
adrp x19, sp_m
add x19, x19, :lo12:sp_m // load address of sp
ldr w22, [x19] // load sp
cmp w22, MAXVAL // compare sp to MAXVAL
b.ge push_ge // if sp >= MAXVAL, stack is full so branch to push_ge
ldr x21, =val_m // load address of val array into x21
str w9, [x21, w22, SXTW 2] // store value of f in array, using val_m as the base and sp_m as the offset
add w22, w22, 1 // sp++
str w22, [x19] // store sp back
b push_ret
push_ge: adrp x0, str1
add w0, w0, :lo12:str1
bl printf
bl clear
push_ret: ldp fp, lr, [sp], 16
ret
pop: stp x29, x30, [sp, -16]!
mov x29, sp
adrp x19, sp_m
add x19, x19, :lo12:sp_m // load address of sp
ldr w22, [x19] // load sp
cmp w22, 0 // compare sp to 0
b.le pop_le // if sp <= 0, stack is empty so branch to pop_le
sub w22, w22, 1 // --sp
str w22, [x19] // store sp back
ldr x21, =val_m // load address of val array into x21
ldr w0, [x21, w22, SXTW 2] // load last value in val array, using val_m as the base and sp_m as the offset
b pop_ret
pop_le: adrp x0, str2
add w0, w0, :lo12:str2
bl printf
bl clear
pop_ret: ldp fp, lr, [sp], 16
ret
Any way to fix this?

How to use BMI function in ARMv8

Currently doing a project for school in Arm Assembly and I've run into a strange problem early on. The program takes two integers as input and is supposed to print the first integer and then, print the absolute value of that integer. The problem is that when I input a negative value, I can't find a way to identify that it is negative, as no matter what kind of branch condition I use the branch is not taken.
This is in Armv8, I've tried to compare the value in x1 to #0 and use BLT and BMI both, but it seems that in either case the branch is not taken. Interestingly the value is always printed as negative, so I'm very confused as to how this works.
.data
newline: .asciz "\n"
input_fmt: .asciz "%d %d"
output_fmt: .asciz "%d"
strfmt: .asciz "hello"
num1: .space 256
num2: .space 256
.text
.global main
main:
//take input
ldr x0, =input_fmt
ldr x1, =num1
ldr x2, =num2
bl scanf
ldr x0, =output_fmt
ldr x1, =num1
ldr x1, [x1]
bl printf
ldr x1, =num1
ldr x1, [x1]
cmp x1, #0 //<---- PROBLEM
bmi ABS //Branch is never taken, even when input is negative
ldr x0, =output_fmt
bl printf
b exit
ABS:
neg x1, x1
br x30
exit:
mov x0, #0
mov x8, #93
svc #0

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