在没有Glibc的情况下,如何在C中使用内联汇编获取参数值? [英] How Get arguments value using inline assembly in C without Glibc?
问题描述
如何在不使用Glibc的情况下使用C中的内联汇编获取参数值?
How Get arguments value using inline assembly in C without Glibc?
对于Linux
体系结构x86_64
和i386
,我需要此代码.
如果您了解MAC OS X
或Windows
,请同时提交并进行指导.
i require this code for Linux
archecture x86_64
and i386
.
if you know about MAC OS X
or Windows
, also submit and please guide.
void exit(int code)
{
//This function not important!
//...
}
void _start()
{
//How Get arguments value using inline assembly
//in C without Glibc?
//argc
//argv
exit(0);
}
新更新
https://gist.github.com/apsun/deccca33244471c1849d29cc6bb5c78e
New Update
https://gist.github.com/apsun/deccca33244471c1849d29cc6bb5c78e
和
#define ReadRdi(To) asm("movq %%rdi,%0" : "=r"(To));
#define ReadRsi(To) asm("movq %%rsi,%0" : "=r"(To));
long argcL;
long argvL;
ReadRdi(argcL);
ReadRsi(argvL);
int argc = (int) argcL;
//char **argv = (char **) argvL;
exit(argc);
但是它仍然返回0. 所以这段代码是错误的! 请帮忙.
But it still returns 0. So this code is wrong! please help.
推荐答案
如注释中所述,堆栈中提供了argc
和argv
,因此即使使用以下命令,也无法使用常规C函数来获取它们:内联汇编,因为编译器将触摸堆栈指针以分配局部变量,因此请设置堆栈框架& co .;因此,_start
必须用汇编语言编写,就像在glibc中一样( x86_64 ).可以编写一个小存根以仅抓取内容,然后根据常规调用约定将其转发到真正的" C入口点.
As specified in the comment, argc
and argv
are provided on the stack, so you cannot use a regular C function to get them, even with inline assembly, as the compiler will touch the stack pointer to allocate the local variables, setup the stack frame & co.; hence, _start
must be written in assembly, as it's done in glibc (x86; x86_64). A small stub can be written to just grab the stuff and forward it to your "real" C entrypoint according to the regular calling convention.
下面是读取argc
和argv
的程序(针对x86和x86_64)的最小示例,在stdout上打印argv
中的所有值(用换行符分隔),并以argc
作为状态退出代码;可以使用通常的gcc -nostdlib
(和-static
来确保不涉及ld.so
;不是在这里有任何危害)进行编译.
Here a minimal example of a program (both for x86 and x86_64) that reads argc
and argv
, prints all the values in argv
on stdout (separated by newline) and exits using argc
as status code; it can be compiled with the usual gcc -nostdlib
(and -static
to make sure ld.so
isn't involved; not that it does any harm here).
#ifdef __x86_64__
asm(
".global _start\n"
"_start:\n"
" xorl %ebp,%ebp\n" // mark outermost stack frame
" movq 0(%rsp),%rdi\n" // get argc
" lea 8(%rsp),%rsi\n" // the arguments are pushed just below, so argv = %rbp + 8
" call bare_main\n" // call our bare_main
" movq %rax,%rdi\n" // take the main return code and use it as first argument for...
" movl $60,%eax\n" // ... the exit syscall
" syscall\n"
" int3\n"); // just in case
asm(
"bare_write:\n" // write syscall wrapper; the calling convention is pretty much ok as is
" movq $1,%rax\n" // 1 = write syscall on x86_64
" syscall\n"
" ret\n");
#endif
#ifdef __i386__
asm(
".global _start\n"
"_start:\n"
" xorl %ebp,%ebp\n" // mark outermost stack frame
" movl 0(%esp),%edi\n" // argc is on the top of the stack
" lea 4(%esp),%esi\n" // as above, but with 4-byte pointers
" sub $8,%esp\n" // the start starts 16-byte aligned, we have to push 2*4 bytes; "waste" 8 bytes
" pushl %esi\n" // to keep it aligned after pushing our arguments
" pushl %edi\n"
" call bare_main\n" // call our bare_main
" add $8,%esp\n" // fix the stack after call (actually useless here)
" movl %eax,%ebx\n" // take the main return code and use it as first argument for...
" movl $1,%eax\n" // ... the exit syscall
" int $0x80\n"
" int3\n"); // just in case
asm(
"bare_write:\n" // write syscall wrapper; convert the user-mode calling convention to the syscall convention
" pushl %ebx\n" // ebx is callee-preserved
" movl 8(%esp),%ebx\n" // just move stuff from the stack to the correct registers
" movl 12(%esp),%ecx\n"
" movl 16(%esp),%edx\n"
" mov $4,%eax\n" // 4 = write syscall on i386
" int $0x80\n"
" popl %ebx\n" // restore ebx
" ret\n"); // notice: the return value is already ok in %eax
#endif
int bare_write(int fd, const void *buf, unsigned count);
unsigned my_strlen(const char *ch) {
const char *ptr;
for(ptr = ch; *ptr; ++ptr);
return ptr-ch;
}
int bare_main(int argc, char *argv[]) {
for(int i = 0; i < argc; ++i) {
int len = my_strlen(argv[i]);
bare_write(1, argv[i], len);
bare_write(1, "\n", 1);
}
return argc;
}
请注意,这里忽略了一些微妙之处-特别是atexit
位.有关特定于机器的启动状态的所有文档已从上面链接的两个glibc文件中的注释中提取.
Notice that here several subtleties are ignored - in particular, the atexit
bit. All the documentation about the machine-specific startup state has been extracted from the comments in the two glibc files linked above.
这篇关于在没有Glibc的情况下,如何在C中使用内联汇编获取参数值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!