title: ARM64 process command line arguments in assembly keywords:raspi5,asm,c,kernel,arm64 # ARM64 process command line arguments in assembly ## Intro Goal is to learn how to get command line arguments in assembly and do basic processing for Linux kernel, all is tested with Raspberry Pi4 on 64bit OS. ## Location of arguments Operating system provides number of arguments, command line arguments and environment variables. Pointers for those located in stack and location of actual values also reference in allocated stack from operating system. ## Checking for argument number Number of arguments passed to command line utility is located at stack pointers first value. Argument number located at _sp_ address, after that there is arguments here we check number of arguments if there is less then 1, it always more then 1 as first argument is always program calling path ```c ldr x3, [sp] cmp x3, #1 b.LE exit_program ``` ## Printing out all arguments Pointers to the argument values are after the stack pointers first value. As first value in stack pointer is number of arguments passed then need to ensure to not go over it. ### Write strlen function There is no default strlen instruction in assembly, so need to write one our-self. I used _x0_ as input argument, _x1_ as internal counter _w2_ to get and compare string char and _x1_ is where final amount of characters is saved. ```c //param 0: x0 pointer to string //using registers: x2 //return result in x1: strlen: mov x1, #0 //number of arguments loop_strlen_till_0: //check if str[] element is 0 ldrb w2, [x0] //ldrb w2, [x2] //if element of string is zero then exit cbz w2, string_element_eq_zero //if element isnt 0 then add +1 to counted size add x1, x1, 1 //increase str pointer +1 add x0, x0, #1 b loop_strlen_till_0 string_element_eq_zero: ret ``` ### Printing out all arguments passed Next step is to utilize strlen function and printout all arguments passed from command line ```c argument_print_loop: //number of arguments now in x4 //get the value of the first argument //add x0, sp, #8 mov x0, x4 ldr x0, [x0] //x0 points to firt argument of programm name bl strlen //write mov x2, x1 mov x0, #1 //set stdout ldr x1, [x4] //point to programm name //ldr x5, =program_len //hopefully correct size of print_arg //ldr x2, [x5] mov w8, #64 svc #0 //print new line mov x0, #1 //set stdout ldr x1, =new_line //point to newline mov x2, #1 mov w8, #64 svc #0 add x4, x4, #8 sub x3, x3, 1 cmp x3, 1 b.GE argument_print_loop ``` All programm seems to work ok ## Source code Final source code of this example ```c .data hello_world: .ascii "print arg program\n" hello_world_len = . - hello_world new_line: .ascii "\n" program_len: .quad 11 .text .global _start _start: //save to x0 number of arguments ldr x3, [sp] //save to x1 address of first argument add x4, sp, #8 //write hello world mov x0, #1 ldr x1, =hello_world ldr x2, =hello_world_len mov w8, #64 svc #0 argument_print_loop: //number of arguments now in x4 //get the value of the first argument mov x0, x4 ldr x0, [x0] //x0 points to firt argument of programm name bl strlen //write mov x2, x1 mov x0, #1 //set stdout ldr x1, [x4] //point to programm name mov w8, #64 svc #0 //print new line mov x0, #1 //set stdout ldr x1, =new_line //point to newline mov x2, #1 mov w8, #64 svc #0 add x4, x4, #8 sub x3, x3, 1 cmp x3, 1 b.GE argument_print_loop exit_program: //exit(0) ldr x0, #0 mov w8, #93 svc #0 //param 0: x0 pointer to string //using registers: x2 //return result in x1: strlen: mov x1, #0 //number of arguments loop_strlen_till_0: //check if str[] element is 0 ldrb w2, [x0] //ldrb w2, [x2] //if element of string is zero then exit cbz w2, string_element_eq_zero //if element isnt 0 then add +1 to counted size add x1, x1, 1 //increase str pointer +1 add x0, x0, #1 b loop_strlen_till_0 string_element_eq_zero: ret ``` ## Comilation size |Program name |Uncompressed size|Compressed size| |---|---|---| |print_arg| 1552 bytes | 481 bytes | ## Links [Make tiny binary](/writeup/arm64_make_tiny_binary.md)