Print 2nd command line argument

2019-02-26 23:40发布

问题:

I'm writing a code that prints out the 2nd argument of a program. I understand that ebp+8 holds number of argument, ebp+12 holds address of name of program and so on. So far I have:

%include "asm_io.inc"

SECTION .data
err1: db "Incorrect number of command line arguments",10,0

SECTION .text 
    global  asm_main

asm_main:
   enter 0,0
   pusha

   mov eax, dword [ebp+8]
   cmp eax, dword 2
   jne ERR1

   mov eax, dword [ebp+16]  ; prints 1st letter of 2nd argument
   mov al, byte[eax]
   call print_string
   jmp asm_main_end


 ERR1:
   mov eax, err1
   call print_string
   jmp asm_main_end

 asm_main_end:
   call print_nl
   popa                  ; restore all registers
   leave                     
   ret

The executable is called lynarr. When I execute lynarr abcd, I'm able to print the program name (ie lynarr) but I don't understand how to print the 2nd argument. I'm using redhat-linux and nasm 2.10.07. Any ideas?

回答1:

dword [ebp+12] is a pointer to an array of string pointers. The first element of that array is a pointer to the first string, the second element is a pointer to the second string etc. Each pointer is 32-bits (4 bytes) wide.

To get a pointer to the second string would require getting the pointer at dword [ebp+12] + 4. You can't do that directly in x86 addressing. You can do it by moving dword [ebp+12] into a register like EAX, add 4 to it (since a pointer is 4 bytes wide) and then dereference that to get a pointer of the second string.

Replace:

mov eax, dword [ebp+16]  ; prints 1st letter of 2nd argument
mov al, byte[eax]
call print_string

With:

mov eax, dword [ebp+12]  
mov eax, [eax+4]          ; EAX = pointer to 2nd argument
call print_string

This would print out the second argument. The first argument can be printed out with:

mov eax, dword [ebp+12]  
mov eax, [eax]           ; EAX = pointer to 1st argument
call print_string

Of course mov eax, [eax+8] would get the 3rd argument and so on.

You can't use print_string to print a single character in a register (like AL). EAX must be a pointer to a NUL(\0) terminated string.


Something else you can do is use scaled index addressing to step through an array (like your arguments):

mov ebx, dword [ebp+12]  
xor esi, esi            ; Index of first argument (index=0) 
mov eax, [ebx+esi*4]    ; EAX = pointer to 1st argument
call print_string
inc esi                 ; Next argument (index=1)
mov eax, [ebx+esi*4]    ; EAX = pointer to 2nd argument
call print_string
inc esi                 ; Next argument (index=2)
mov eax, [ebx+esi*4]    ; EAX = pointer to 3rd argument
call print_string

With this idea you can probably see how you can create a loop that goes through the arguments. I leave that as an exercise for the reader. This is another handy quick reference for addressing modes.