Author Topic: NASM Assembly x86-64 - Help on looping command line arguments  (Read 7223 times)

Offline VGB1526

  • Jr. Member
  • *
  • Posts: 2
Hello, I'm new on assembly and am having problems with a program I am trying to create. The program is supposed to display the number of arguments given by the user and each of the arguments the user entered. It should also display a message when no argument is given (By not counting the program invoking statement as an argument). I am having trouble figuring out how to loop the arguments so that the program will display all of the arguments no matter how many is given by the user. Does anyone know how I can solve this problem? Thanks!

Here is the code:
Code: [Select]
%include ""

global main ;entry point for assembly
extern puts

section .text
  push rdi ;save to stack
  push rsi ;save to stack

;show # of arguments
  mov rax, rdi
  call WriteDec

;put blank line
  mov rdi, blankline
  call puts

;if more than 1 argument is given then jump to great
  mov rcx, 1
  cmp rcx, rdi
  jg great

  jmp less
;return original values
  pop rsi
  pop rdi
;show items
  push rdi          ;save to stack
  push rsi
  sub rsp, 8 ;align stack boundary
  add rsi, 8        ;move address to next item
  mov rdi, [rsi]  ;argument from command line
  call puts
cmp rsi, rdi
  jne loop
  add rsp, 8 ;realign boundary
  pop rsi            ;restore registers
  pop rdi

  jmp skip
  pop rsi
  pop rdi

;display noarg message
  mov rax, 1
  mov rsi, noarg
  mov rdx, noarglength

  jmp end

;display end message
  mov rax, 1
  mov rsi, endmessage
  mov rdx, endmessagelength

  ret ;close C functions

section .data
  blankline: db " ",0

  noarg: db 'No arguments found.',0,0ah
  noarglength: equ ($-noarg)

  endmessage: db 'The program is completed',0,0ah
  endmessagelength: equ ($-endmessage)
« Last Edit: April 19, 2020, 10:43:45 PM by VGB1526 »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 371
  • Country: br
Re: NASM Assembly - Help on looping command line arguments
« Reply #1 on: April 19, 2020, 05:28:34 PM »
The command line arguments, on Linux, works the same way as in the main() function in C, but the arguments are pushed to stack, instead of using registers (in x86-64 mode):

Code: [Select]
int main( int argc, char *argv[] );
RSP points to a QWORD containing argc, RSP+8 to argv[0], RSP+16 to argv[1], ... until argv[argc] == NULL (0).

Code: [Select]
  mov ecx,[rsp]           ; get argc in ECX, if you need it.

  xor esi,esi             ; let's start with n = 0.
  mov rdi,[rsp+rsi*8+8]   ; get argv[n].

  test  rdi,rdi           ; Is argv[n] == NULL?
  jz    .exit_loop        ; yes... exit loop

  ; Do something with RDI (argv[n]) here.
  ; Don't forget to preserve RDI, RSI and RSP.

  add  esi,1              ; n++
  jmp  .loop
  ; ...

The glibc will get these values from stack and pass them as arguments to main(), using x86-64 SysV calling convention. But they are passed to your program through the stack.

But, if you are using libc functions, why to write your code in assembly, since you'll need to link libc and initialize it anyway?
« Last Edit: April 19, 2020, 05:56:17 PM by fredericopissarra »