ARM legV8 Program received signal SIGSEGV, Segmentation fault - gcc

I have recently wrote this code in assembly (ARM legV8) which uses recursion to calculate gcd between 64 bit random numbers. In the first place i generate 2 random numbers using random() and then i check if the are relatively prime ( gcd(num1,num2) == 1). If not then generate new numbers. Repeat until relatively prime numbers are found. The random() and gcd() functions are working fine (checked). I have an issue with the stack (Segmentation fault) when i try to store on it an updated value. I get error on the third time i call the loop on that line str x22,[x29,24] Here is my code :
.data //Start of the datasegment
q_initialState: .string "Please enter the intial state : "
scanner_hex: .string "%p"
output_num: .string "%llu\n"
gcd_result: .string "GCD is : %d\n"
message: .string "They are prime numbers \n"
.text //Start of the .text segment
.global main
main:
stp x29,x30,[sp,-32]!
add x29,sp,0
adr x0,q_initialState
bl printf
add x1,x29,28
adr x0,scanner_hex
bl scanf
ldr x19,[x29,28] //this is the initial state
loop:
mov x2,x19
bl random
mov x22,x5
mov x1,x22
adr x0,output_num
bl printf
mov x2,x19
bl random
mov x23,x5
mov x1,x23
adr x0,output_num
bl printf
str x22,[x29,24] // <----------- ERROR HERE ---------
str x23,[x29,28]
bl gcd
cmp x24,1
bne loop
ldp x29,x30,[sp],32
ret
random:
stp x29,x30,[sp,-32]!
add x29,sp,0
eor x2,x2,x2,lsr 12
eor x2,x2,x2,lsl 25
eor x2,x2,x2,lsr 27
ldr x4,=0x2545f4914f6cdd1d
mul x5,x2,x4
mov x19,x2
ldp x29,x30,[sp],32
ret
gcd:
stp x29,x30,[sp,-32]!
add x29,sp,0
ldr x9,[x29,56] //Value for variable m
ldr x10,[x29,60] //Value for variable n
udiv x11,x9,x10
mul x11,x11,x10
sub x1,x9,x11
cbz x1,return_n
str x10,[x29,24]
str x1,[x29,28]
bl gcd
ldp x29,x30,[sp],32
ret
return_n:
ldr x1,[x29,60]
mov x24,x1
ldp x29,x30,[sp],32
ret

Related

How to use _scanf in Apple Silicon (aarch64 macos) assembly to read in user input? [duplicate]

This question already has an answer here:
Calling printf from aarch64 asm code on Apple M1 / MacOS
(1 answer)
Closed last month.
I'm new to assembly programming, but I've been figuring a lot out by googling and trial and error. I'm trying to write a simple program that prompts the user to enter a number (with _printf), then reads in and saves that number (_scanf), then prints out a message using the stored number (_printf).
I was able to get the _printf code to work under aarch64 (Apple Silicon) assembly, but no matter what I do, I cannot seem to get _scanf to work. I have looked through the ARM Developer docs, looked at the HelloSilicon github page, and googled for hours, and I cannot come up with anything that works.
In my code (included below), if I comment out the "read_from_keyboard" branch in the following code, the printf functions work just fine. But when I include the "read_from_keyboard" code, I get a "Segmentation fault: 11" error.
Where is my mistake?
.global main
.align 4
main:
// PRINT MESSAGE
ADRP X0, message#PAGE
ADD X0, X0, message#PAGEOFF
BL _printf
// BL read_from_keyboad
// READ NUMBER FROM DATA AND MOVE TO STACK FOR PRINTING
ADRP X10, num#PAGE
ADD X10, X10, num#PAGEOFF
LDR X1, [X10]
STR X1, [SP, #-16]!
// LOAD THE PRINTF FORMATTED MESSAGE
ADRP X0, output_format#PAGE
ADD X0, X0, output_format#PAGEOFF
end:
BL _printf
mov X16, #1
svc 0
read_from_keyboard:
ADRP X0, input_format#PAGE
ADD X0, X0, input_format#PAGEOFF
ADRP X11, num#PAGE
ADD X11, X11, num#PAGEOFF
BL _scanf
ret
.data
.balign 4
message: .asciz "What is your favorite number?\n"
.balign 4
num: .word 32
.balign 4
input_format: .asciz "%d"
.balign 4
output_format: .asciz "Your favorite number is %d \n"
On the call to _printf, your variadic arg is in [sp]. On the call to _scanf, you put it in x11. Why? Just do the same str xN, [sp, #-16]! that you do on _printf, that'll fix your segfault.
In addition though, you also need a stack frame for read_from_keyboard. The bl _scanf clobbers x30, so the following ret would just get stuck in an infinite loop.
Fix these two issues and your code works:
.global _main
.align 4
_main:
// PRINT MESSAGE
ADRP X0, message#PAGE
ADD X0, X0, message#PAGEOFF
BL _printf
BL read_from_keyboard
// READ NUMBER FROM DATA AND MOVE TO STACK FOR PRINTING
ADRP X10, num#PAGE
ADD X10, X10, num#PAGEOFF
LDR X1, [X10]
STR X1, [SP, #-16]!
// LOAD THE PRINTF FORMATTED MESSAGE
ADRP X0, output_format#PAGE
ADD X0, X0, output_format#PAGEOFF
end:
BL _printf
mov X16, #1
svc 0
read_from_keyboard:
STP X29, X30, [SP, #-16]!
ADRP X0, input_format#PAGE
ADD X0, X0, input_format#PAGEOFF
ADRP X11, num#PAGE
ADD X11, X11, num#PAGEOFF
STR X11, [SP, #-16]!
BL _scanf
ADD SP, SP, #16
LDP X29, X30, [SP], #16
ret
.data
.balign 4
message: .asciz "What is your favorite number?\n"
.balign 4
num: .word 32
.balign 4
input_format: .asciz "%d"
.balign 4
output_format: .asciz "Your favorite number is %d \n"

Capture input in assembly arm 64 bit mac os

Trying to capture two characters and new line from user input.
The program prints the 3 helloworlds to screen and then users can type in some characters.
Everything seems to work, but it doesn't print the input
I suspect it is due to the way I operate on the X1 register in the _read function, or the way the buffer is allocated
No errors are reported when running the code.
The code is compiled using the following command. It should run on a Mac M1
as HelloWorld.s -o HelloWorld.o && ld -macosx_version_min 12.0.0 -o HelloWorld HelloWorld.o -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 && ./HelloWorld
//HelloWorld.s
.equ SYS_WRITE, 4
.equ SYS_READ, 3
.equ NEWLN, 10
.global _start // Provide program starting address to linker
.align 2
// Setup the parameters to print hello world
// and then call Linux to do it.
_start:
adr X4, helloworld1
mov X1, X4
bl _sizeof
bl _print
adr X4, helloworld2
mov X1, X4
bl _sizeof
bl _print
adr X4, helloworld3
mov X1, X4
bl _sizeof
bl _print
bl _read
//mov X2, 4
// bl _sizeof
bl _print
_exit:
mov X0, X2 // Use 0 return code
mov X16, #1 // Service command code 1 terminates this program
svc 0 // Call MacOS to terminate the program
_sizeof: //X1 = address, X2 = out length, string must terminate with \n
str LR, [SP, #-16]! //Store registers
//str W0, [SP, #-16]!
mov X2, #0
__loop:
ldrb W0, [X1, X2] //load a byte into W0 (32 bit)
add X2, X2, #1 //Add 1 offset
cmp W0, NEWLN //Compare byte with \n return
bne __loop
//ldr W0, [SP], #16
ldr LR, [SP], #16 //Load registers
ret
_print: //X2 = length, X1 = address
str LR, [SP, #-16]! //Store registers
mov X0, #1 // 1 = StdOut
// mov X1, X1 // string to print
// mov X2, X2 // length of string
mov X16, SYS_WRITE // MacOS write system call
svc 0 // Call kernel to output the string
ldr LR, [SP], #16 //Load registers
ret
_read:
//3 AUE_NULL ALL { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); }
str LR, [SP, #-16]! //Store registers
adr X1, msg
mov X0, #0 // 0 = StdIn
ldr X1, [x1] // address to store string
mov X2, #4 // length
mov X16, SYS_READ // MacOS read system call
svc 0 // Call system
ldr LR, [SP], #16 //Load registers
ret
msg: .ds 4 //memory buffer for keyboard input
helloworld1: .ascii "Hello World\n"
helloworld2: .ascii "Happy new year for 2022\n"
helloworld3: .ascii "Welcome to AARCH64 assembly on Mac Silicon\n"
First you need to move msg to a writeable segment:
.data
msg: .ds 4 //memory buffer for keyboard input
.text // keep everything else in __TEXT
Then, because segments may be moved around arbitrarily at link-time, Apple's toolchain will no longer allow you to use adr to get the address of that buffer - you will have to use adrp and add:
adrp x1, msg#page
add x1, x1, msg#pageoff
If you want, you can tell the linker to please optimise this back to an adr if possible:
Lloh0:
adrp x1, msg#page
Lloh1:
add x1, x1, msg#pageoff
.loh AdrpAdd Lloh0, Lloh1
Then you need to remove this line:
ldr X1, [x1]
That would load the contents of the buffer, which would just be null bytes.
And finally, you should change the x0 value to exit to a constant:
mov x0, 0
The value in x2 will have been clobbered at this point, and you don't need it anyway.
As a reference for anyone in the future looking for an example to read from Standard In on AppleSilicon (M1), this code (based on the above information) works. It takes in a string up to 20 characters and prints it back out to the Standard Output.
.global _start
.align 2
_start:
// READ IN FROM KEYBOARD
mov X16, 3 // Tell system we want to read from StdIn (#3)
mov X0, 0 // Focus on the keyboard (#0)
mov X2, 20 // Define length of string to read in
adrp x1, msg#page // Load the address of the message
add x1, x1, msg#pageoff // Store the address to x1
svc 0 // Call kernel to perform the action
_write:
mov X16, 4 // Tell system we want to write to StdOut (#4)
mov X0, 1 // Focus on the screen (#1)
adrp x1, msg#page // Load the address of the message
add x1, x1, msg#pageoff // Store the address to x1
svc 0 // Call kernel to perform the action
_end:
mov X0, 0 // Return 0 (get a run error without this)
mov X16, 1 // System call to terminate this program
svc 0 // Call kernel to perform the action
.data
msg:
.ds 20 // 20 bytes of memory for keyboard input
Your makefile should look like this:
temp: temp.o
ld -o temp temp.o -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64
temp.o: temp.s
as -arch arm64 -o temp.o temp.s

How to Modify a String in Arm Assembly [duplicate]

So I'm having trouble with my program. It's supposed to read in a text file
that has a number on each line. It then stores that in an array, sorts it using selection sort, and then outputs it to a new file. The reading of and writing to the file work perfectly fine but my code for the sort isn't working properly. When I run the program, it only seems to store some of the numbers
in the array and then a bunch of zeroes.
So if my input is 112323, 32, 12, 19, 2, 1, 23. The output is 0,0,0,0, 2,1,23. I'm pretty sure the problem's with how I'm storing and loading from the array
onto the registers because assuming that part works, I can't find any reason why the selection sort algorithm shouldn't work.
Ok thanks to your help, I figured out that I needed to change the load and store instruction so that it matches the specifier used (ldr -> ldrb and str -> strb). But I need to make a sorting algorithm that works for 32 bit numbers so which combination of specifiers and load/store instructions would allow me to do that? Or would I have to load/store 8 bits a time? And if so, how would I do that?
.data
.balign 4
readfile: .asciz "myfile.txt"
.balign 4
readmode: .asciz "r"
.balign 4
writefile: .asciz "output.txt"
.balign 4
writemode: .asciz "w"
.balign 4
return: .word 0
.balign 4
scanformat: .asciz "%d"
.balign 4
printformat: .asciz "%d\n"
.balign 4
a: .space 32
.text
.global main
.global fopen
.global fprintf
.global fclose
.global fscanf
.global printf
main:
ldr r1, =return
str lr, [r1]
ldr r0, =readfile
ldr r1, =readmode
bl fopen
mov r4, r0
mov r5, #0
ldr r6, =a
loop:
cmp r5, #7
beq sort
mov r0, r4
ldr r1, =scanformat
mov r2, r6
bl fscanf
add r5, r5, #1
add r6, r6, #1
b loop
sort:
mov r5,#0 /*array parser for first loop*/
mov r6, #0 /* #stores index of minimum*/
mov r7, #0 /* #temp*/
mov r8, #0 /*# array parser for second loop*/
mov r9, #7 /*# stores length of array*/
ldr r10, =a /*# the array*/
mov r11, #0 /*#used to obtain offset for min*/
mov r12, #0 /*# used to obtain offset for second parser access*/
loop3:
cmp r5, r9 /*# check if first parser reached end of array*/
beq write /* #if it did array is sorted write it to file*/
mov r6, r5 /*#set the min index to the current position*/
mov r8, r6 /*#set the second parser to where first parser is at*/
b loop4 /*#start looking for min in this subarray*/
loop4:
cmp r8, r9 /* #if reached end of list min is found*/
beq increment /* #get out of this loop and increment 1st parser**/
lsl r7, r6, #3 /*multiplies min index by 8 */
ADD r7, r10, r7 /* adds offset to r10 address storing it in r7 */
ldr r11, [r7] /* loads value of min in r11 */
lsl r7, r8, #3 /* multiplies second parse index by 8 */
ADD r7, r10, r7 /* adds offset to r10 address storing in r7 */
ldr r12, [r7] /* loads value of second parse into r12 */
cmp r11, r12 /* #compare current min to the current position of 2nd parser !!!!!*/
movgt r6, r8 /*# set new min to current position of second parser */
add r8, r8, #1 /*increment second parser*/
b loop4 /*repeat */
increment:
lsl r11, r5, #3 /* multiplies first parse index by 8 */
ADD r11, r10, r11 /* adds offset to r10 address stored in r11*/
ldr r8, [r11] /* loads value in memory address in r11 to r8*/
lsl r12, r6, #3 /*multiplies min index by 8 */
ADD r12, r10, r12 /*ads offset to r10 address stored in r12 */
ldr r7, [r12] /* loads value in memory address in r12 to r7 */
str r8, [r12] /* # stores value of first parser where min was !!!!!*/
str r7, [r11] /*# store value of min where first parser was !!!!!*/
add r5, r5, #1 /*#increment the first parser*/
ldr r0,=printformat
mov r1, r7
bl printf
b loop3 /*#go to loop1*/
write:
mov r0, r4
bl fclose
ldr r0, =writefile
ldr r1, =writemode
bl fopen
mov r4, r0
mov r5, #0
ldr r6, =a
loop2:
cmp r5, #7
beq end
mov r0, r4
ldr r1, =printformat
ldrb r2, [r6]
bl fprintf
add r5, r5, #1
add r6, r6, #1
b loop2
end:
mov r0, r4
bl fclose
ldr r0, =a
ldr r0, [r0]
ldr lr, =return
ldr lr, [lr]
bx lr
I figured out that I needed to change the load and store instruction
so that it matches the specifier used (ldr -> ldrb and str -> strb).
But I need to make a sorting algorithm that works for 32 bit numbers
so which combination of specifiers and load/store instructions would
allow me to do that?
If you want to read 32b (4 bytes) values from memory, you have to have 4 bytes values in memory to begin with. Well that should not be surprising :)
Eg if your input is numbers 1, 2, 3, 4, each number is 32b value than in memory that would be
0x00000000: 01 00 00 00 | 02 00 00 00 <- 32b values of 1 & 2
0x00000008: 03 00 00 00 | 04 00 00 00 <- 32b values of 3 & 4
In such case ldr would read 32b each time and you would get 1, 2, 3, 4 with each read in register.
Now, you have in memory byte values (based on your statement that `ldrb` gives right result), eg
0x00000000: 01
0x00000001: 02
0x00000002: 03
0x00000003: 04
or same in one line
0x00000000: 01 02 03 04
So reading 8bit by ldrb gives you numbers 1, 2, 3, 4
But ldr would do read 32b value from memory (all 4 bytes at once) and you would get 32b value 0x04030201 in register.
Note: examples for little-endian systems

No output from 8086 program when running ml program.asm in DOSBox

I got this code from the Geeks-for-Geeks site, but there were lots of indentation errors, I changed the code to the following but, when running the code using MASM and DOSBox it's giving no output.
The Output I should get, According to the site I should get 20 but I get nothing, the code is saved as pro.asm, and I'm using DOSBox version 0.74.
For getting the o/p in the DOSBox I did,
mount c c:\8086
c:
ml pro.asm
Code:
;8086 program to convert a 16-bit decimal number to octal
.MODEL SMALL
.STACK 100H
.DATA
d1 dw 16
.CODE
MAIN PROC FAR
MOV ax,#DATA
MOV ds,ax
;load the value stored in variable d1
MOV ax, d1
;convert the value to octal
;print the value
CALL PRINT
;interrupt to exit
MOV AH,4CH
INT 21H
MAIN ENDP
PRINT PROC
;initialize count
MOV cx,0
MOV dx,0
label1: ;if ax is zero
cmp ax,0
je print1
;initialize bx to 8
mov bx, 8
;divide it by 8 to convert it to octal
div bx
;push it in the stack
push dx
;increment the count
inc cx
;set dx to 0
xor dx,dx
jmp label1
print1: ;check if count is greater than zero
cmp cx,0
je exit
;pop the top of stack
pop dx
;add 48 so that it
;represents the ASCII
;value of digits
add dx,48
;interrupt to print a
;character
mov ah,02h
int 21h
;decrease the count
dec cx
jmp print1
exit : ret
PRINT ENDP
END MAIN
The output I'm getting can be seen below
Your code looks okay. Your screenshot shows you have only assembled and linked the code but not actually run it. To run it type:
pro.exe

NASM program doesn't print constant integer (macOS)

I try to print b, but it prints nothing. Also I wanted to find length of b to hardcode it (because dws have the same length), but it printed nothing too (that's why I created lenlen — len of blen, so that I can print blen). Don't pay attention to k and a, they are not used yet.
global _main:
section .data
b: dw 10
blen: equ $-b
lenlen: equ $-blen
k: dw 6
section .bss
a: resw 1
section .text
_main:
mov rax, 0x2000004
mov rdi, 1
mov rsi, b
mov rdx, blen
syscall
mov rax, 0x2000001
mov rdi, 0
syscall

Resources