问题
I actually wanted to write a program in assembly(linux) , to accept filename from the command line and I was successful by retrieving the values from the stack using successive pop opcodes when I used "ld" command to build but I was unsuccessful when i used "gcc" command . I need to use gcc because I will be using various C std library function in this program.
Actually the file was creating , but its always got a "Invalid encoding " label and appeared like <? G ?
in the directory.I wanted to know:
- Do we follow a different procedure when built using gcc tools
- What was the possible reason for an invalid encoding file being created (out of curiosity).
Here is a sample code that works with ld but not with gcc.
section .data
filename: db 'testing',0
section .text
;extern printf ;to be uncommented when using gcc
;extern scanf ; -do-
global _start ; replace with main when using gcc
_start: ; replace with main:
pop ebx ; argc (argument count)
pop ebx ; argv[0] (argument 0, the program name)
pop ebx ; The first real arg, a filename
mov eax,8
; issue: ebx is not holding the filename popped from cli using gcc
;mov ebx,filename ; filename as a constant works with gcc but cli?
mov ecx,00644Q ; Read/write permissions in octal (rw_rw_rw_)
int 80h ; Call the kernel
; Now we have a file descriptor in eax
test eax,eax ; Lets make sure the file descriptor is valid
js terminate ; If the file descriptor has the sign flag
call fileWrite
terminate:
mov ebx,eax ; If there was an error, save the errno in ebx
mov eax,1 ; Put the exit syscall number in eax
int 80h ; control over to kernel
fileWrite: ; simply closing the file for time being
mov ebx,eax ; edited
mov eax,6 ; sys_close (ebx already contains file descriptor)
int 80h
call terminate
Solution and Caveat: There is a difference in the stack when using libc or bare-bone assembly.
When using libc the , the first pop returns the return address followed by argc and argv values respectively.
In bare-bone assembly , the first pop return the argc ,and every pop hence gives the successive argv values unlike a arguments pointer returned when using libc.
Source: Reading filename from argv via x86 assembly
回答1:
This blog post explains how the stack looks like when the entry point of a program is being called: http://eli.thegreenplace.net/2012/08/13/how-statically-linked-programs-run-on-linux
In a nutshell, you have these elements on the stack:
argc
argv[0]
- program/executable nameargv[1]
...argv[argc-1]
- Program argumentsargv[argc]
- AlwaysNULL
envp[0]
...envp[N]
- The current environmentNULL
to terminate theenvp
array
Those pointers are either 32 bit or 64 bit, depending on your kernel. x86
= 32 bit, x64
= 64 bit. So make sure you fetch the correct sizes from the stack. On x64
, argc
takes 8 bytes.
If you want to avoid this hassle, link against libc
and provide a main
entry point instead of _start
. libc
contains _start
which will process the command line argument into arrays and then call main
with three elements on the stack:
int argc
char** argv
char** envp
The startup code of libc
will also initialize the stdio framework; without that, calls to printf()
will fail because stdout
will be a NULL
pointer.
来源:https://stackoverflow.com/questions/28984009/how-to-accept-input-from-command-line-in-a-assembly-program-build-using-gcc-tool