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

  • A+
Category:Languages

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

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); } 

New Update

https://gist.github.com/apsun/deccca33244471c1849d29cc6bb5c78e

and

#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); 

But it still returns 0. So this code is wrong! please help.


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.

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; } 

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.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: