如何在使用gcc工具的汇编程序构建中接受来自命令行的输入? [英] how to accept input from command line in a assembly program build using gcc tools?
问题描述
我实际上想在assembly(linux)中编写一个程序,以从命令行接受文件名,当我使用"ld"命令进行构建时,我成功通过使用连续的弹出操作码从堆栈中检索值而成功,但是当我使用"gcc"命令时不成功.我需要使用gcc,因为我将在此程序中使用各种C std库函数.
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.
实际上该文件正在创建中,但是它始终带有无效编码"标签,并在目录中显示为<? G ?
.我想知道:
Actually the file was creating , but its always got a "Invalid encoding " label and appeared like <? G ?
in the directory.I wanted to know:
- 使用gcc工具进行构建时,我们是否遵循不同的程序
- 出于好奇的原因,创建无效的编码文件的可能原因是什么.
以下是适用于ld的示例代码,但不适用于gcc.
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
解决方案和注意事项: 使用libc或裸骨程序集时,堆栈有所不同.
Solution and Caveat: There is a difference in the stack when using libc or bare-bone assembly.
-
使用libc时,第一个弹出窗口将返回返回地址,并分别返回argc和argv值.
When using libc the , the first pop returns the return address followed by argc and argv values respectively.
在准系统中,第一个pop返回argc,因此每个pop都给出了连续的argv值,这与使用libc时返回的参数指针不同.
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.
推荐答案
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]
-程序/可执行名称 -
argv[1]
...argv[argc-1]
-程序参数 -
argv[argc]
-始终为NULL
-
envp[0]
...envp[N]
-当前环境 -
NULL
终止envp
数组
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
这些指针是32位还是64位,具体取决于您的内核. x86
= 32位,x64
= 64位.因此,请确保从堆栈中获取正确的大小.在x64
上,argc
占用8个字节.
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.
如果要避免这种麻烦,请链接libc
并提供main
入口点而不是_start
. libc
包含_start
,它将把命令行参数处理为数组,然后使用堆栈中的三个元素调用main
:
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
int argc
char** argv
char** envp
libc
的启动代码也将初始化stdio框架;否则,由于stdout
将是NULL
指针,因此对printf()
的调用将失败.
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.
这篇关于如何在使用gcc工具的汇编程序构建中接受来自命令行的输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!