在没有Glibc的情况下,如何在C中使用内联汇编获取参数值? [英] How Get arguments value using inline assembly in C without Glibc?

查看:122
本文介绍了在没有Glibc的情况下,如何在C中使用内联汇编获取参数值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在不使用Glibc的情况下使用C中的内联汇编获取参数值?

How Get arguments value using inline assembly in C without Glibc?

对于Linux体系结构x86_64i386,我需要此代码. 如果您了解MAC OS XWindows,请同时提交并进行指导.

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.

推荐答案

如注释中所述,堆栈中提供了argcargv,因此即使使用以下命令,也无法使用常规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.

下面是读取argcargv的程序(针对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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆