0

Can I get argv[0] through _start instead of main in the C function? I don't use any lib.

void _start(void) __attribute__((noreturn));
 void _start(void)
 {
   //how can get argv[0] here . I don't use main as my first entry.
 }
  • 1
    There's no portable way. What architecture are you on? – Joseph Sible-Reinstate Monica Nov 22 '20 at 17:24
  • Assuming `_start` has been made the entry point for your program, you would have to mark this function as naked with `__attribute__((naked))` to remove function prologue and epilogue and then you would have to write `asm` code that directly address the parameters passed to a process (rather than the C library). The layout of the stack is in the System V ABI (there is an ABI for x86 and x86-64) so it depends on whether you are writing 32-bit or 64-bit code but both are similar. – Michael Petch Nov 22 '20 at 17:25
  • 1
    https://lwn.net/Articles/631631/ <- some info about what's passed to a new process (x64 arch) –  Nov 22 '20 at 17:27
  • I wrote an SO answer that processes command line parameters in assembly (without the C library and C startup) in 64-bit MacOS. The stack layout at process creation is the same as Linux. This answer might give you some ideas: https://stackoverflow.com/a/37230461/3857942 – Michael Petch Nov 22 '20 at 17:35
  • 1
    Essentially in x86 64-bit code the number of arguments passed to the program is stored at `0(%rsp)` (`argc`). The pointer stored at 8(%rsp) is a pointer to `arg[0]` (program name), `16(%rsp)` is a pointer to `argv[1]` etc. In x86 32-bit code `argc` is stored at `0(%esp) `, `4(%esp)` contains a pointer to `arg[0]`, `8(%esp)` contains a pointer to `arg[1]` and so on. If you're on some other architecture (like ARM) you will have to look at the ABI for that platform. That is why it would help to know what architecture you are targeting as Joseph mentioned. I took a guess ay x86 but I may be wrong. – Michael Petch Nov 22 '20 at 17:51

1 Answers1

4

The ELF entry point contract is not a C function in the vast majority of psABIs (processor-specific ABI, the arch-dependent part of ELF). At entry, the stack pointer register points to an array of system-word-sized slots consisting of:

argc, argv[0], ..., argv[argc-1], 0, environ[0], ..., environ[N], 0,
auxv[0].a_type, auxv[0].a_value, ..., 0

You need at least a minimal asm stub to convert this into form that's readable by C. The simplest way to do this is to copy the stack pointer register into the first-argument register, align the stack pointer down according the function call ABI requirements, and call your C function taking a single pointer argument.

You can see the crt_arch.h files (x86_64 version here) in musl libc for an example of how this is done. (You can probably ignore the part about _DYNAMIC which is arranging for self-relocation when the entry point is used in the dynamic linker startup or static PIE executables.)

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711