Cycle Through and Print argv [] in x64 ASM

I worked on a loop whileto get through all the CLI arguments. While working on a solution to print only 1 element, I noticed a few things; it was this process that prompted me here.

I noticed that if I did lea 16(%rsp), %someRegisterToWrite, I was able to get / print argv [1]. Then I tried lea 24(%rsp), %someRTW, and it gave me access to argv [2]. I continued to rise to see if it would continue to work, and this happened.

My thought was to keep adding 8 to %someRTWand increment the counter until the counter is equal to argc. This following code works fine when entering one argument, but does not print anything with two arguments, and when I enter 3 arguments, it will print the first 2 without a gap between them.

.section __DATA,__data
.section __TEXT,__text
.globl _main
_main:
    lea (%rsp), %rbx        #argc
    lea 16(%rsp), %rcx      #argv[1]
    mov $0x2, %r14          #counter
    L1:
    mov (%rcx), %rsi        #%rsi = user_addr_t cbuf
    mov (%rcx), %r10
    mov 16(%rcx), %r11      
    sub %r10, %r11          #Get number of bytes until next arg
    mov $0x2000004, %eax    #4 = write
    mov $1, %edi            #edi = file descriptor 
    mov %r11, %rdx          #user_size_t nbyte
    syscall
    cmp (%rbx), %r14        #if counter < argc
    jb L2
    jge L3
    L2:
    inc %r14                
    mov 8(%rcx), %rcx       #mov 24(%rsp) back into %rcx
    mov $0x2000004, %eax
    mov $0x20, %rsi         #0x20 = space
    mov $2, %rdx
    syscall
    jmp L1
    L3:
    xor %rax, %rax
    xor %edi, %edi
    mov $0x2000001, %eax
    syscall
+3
source share
2 answers

, 64- /X , C. C System, , _main . _start - , , , .

64- ​​ macho64 . Apple OS/X , System V x86-64 ABI 3.4:

Initial Process Stack

, NULL (0). , NULL (0) argc.


, , SYSCALL. SYSCALL RCX R11:

SYSCALL 0. , RIP MSR IA32_LSTAR ( , SYSCALL RCX). ( WRMSR , MS32 IA32_LSTAR .)

SYSCALL RFLAGS R11, RFLAGS, MS32- IA32_FMASK (MSR- C0000084H); , RFLAGS , , IA32_FMASK MSR

- , RCX R11. / SYSCALL , , . clobber RAX .

Apple OS/X . 64- OS/X 0x2000000 :

64- Mach , 0x2000000, POSIX 0x1000000


. . , NUL (0).


:

mov 8(%rcx), %rcx       #mov 24(%rsp) back into %rcx
mov $0x2000004, %eax
mov $0x20, %rsi         #0x20 = space
mov $2, %rdx
syscall

sys_write RSI . , 0x20 (). - ( ) RSI.


( ) . . Darwin OS/X 0x0a (\n).

# In 64-bit OSX syscall numbers = 0x2000000+(32-bit syscall #)
SYS_EXIT  = 0x2000001
SYS_WRITE = 0x2000004

STDOUT    = 1

.section __DATA, __const
newline: .ascii "\n"
newline_end: NEWLINE_LEN = newline_end-newline

.section __TEXT, __text
.globl _main
_main:
    mov (%rsp), %r8             # 0(%rsp) = # args. This code doesn't use it
                                #    Only save it to R8 as an example.
    lea 16(%rsp), %rbx          # 8(%rsp)=pointer to prog name
                                # 16(%rsp)=pointer to 1st parameter
.argloop:
    mov (%rbx), %rsi            # Get current cmd line parameter pointer
    test %rsi, %rsi
    jz .exit                    # If it zero we are finished

    # Compute length of current cmd line parameter
    # Starting at the address in RSI (current parameter) search until
    # we find a NUL(0) terminating character.
    # rdx = length not including terminating NUL character

    xor %edx, %edx              # RDX = character index = 0
    mov %edx, %eax              # RAX = terminating character NUL(0) to look for
.strlenloop:
         inc %rdx               # advance to next character index
         cmpb %al, -1(%rsi,%rdx)# Is character at previous char index
                                #     a NUL(0) character?
         jne .strlenloop        # If it isn't a NUL(0) char then loop again
    dec %rdx                    # We don't want strlen to include NUL(0)

    # Display the cmd line argument
    # sys_write requires:
    #    rdi = output device number
    #    rsi = pointer to string (command line argument)
    #    rdx = length
    #
    mov $STDOUT, %edi
    mov $SYS_WRITE, %eax
    syscall

    # display a new line
    mov $NEWLINE_LEN, %edx
    lea newline(%rip), %rsi     # We use RIP addressing for the
                                #     string address
    mov $SYS_WRITE, %eax
    syscall

    add $8, %rbx                # Go to next cmd line argument pointer
                                #     In 64-bit pointers are 8 bytes
    # lea 8(%rbx), %rbx         # This LEA instruction can replace the
                                #     ADD since we don't care about the flags
                                #     rbx = 8 + rbx (flags unaltered)
    jmp .argloop

.exit:
    # Exit the program
    # sys_exit requires:
    #    rdi = return value
    #
    xor %edi, %edi
    mov $SYS_EXIT, %eax
    syscall

strlen , , . strlen . strlen, Agner Fog .

C, :

gcc -e _main progargs.s -o progargs -nostartfiles -static
+2

, , - cli-arguments. - , , . argc, , . :

add $0x10, %rsp
L0:
  pop %rsi
  or %rsi, %rsi
  jz L2
  mov %rsi, %rdi
  xor %rdx, %rdx
  L1:
    mov (%rsi), %al
    inc %rsi
    inc %rdx
    or %al, %al
  jnz L1
  ;%rdx - len(argument)
  ;%rdi - argument
  ;< do something with the argument >
  jmp L0
L2:

, :).

lea (newline), %rsi
mov $0x02, %rdx
mov STDOUT, %rdi
mov sys_write, %rax
[...]
newline db 13, 10, 0

syscall % rax, , OSX-? , : % rcx (% rip) % r11 (% rflags). intel x86_64: http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf

:

jb L2
jge L3
L2:

argc counter are unsigned, , :

jae L3

, . intel-, , , :)

+2

Source: https://habr.com/ru/post/1690738/


All Articles