Linux getting terminal arguments from _start not working with inline assembly in C

爷,独闯天下 提交于 2021-02-08 08:57:14

问题


I am trying to write my own _start function using inline assembly. But when I try to read argc and argv from stack (%rsp and %rsp + 8) I get wrong values. I don't know what I am doing wrong.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <syscall.h>

int main(int argc, char *argv[]) {
    printf("%d\n", argc);
    printf("%s\n", argv[0]);
    printf("got here\n");
    return 0;
}

void _start() {
    __asm__(
    "xor %rbp, %rbp;"
    "movl (%rsp), %edi;"
    "lea 8(%rsp), %rsi;"
    "xor %rax, %rax;"
    "call main"
...

Terminal:

$ gcc test.c -nostartfiles
$ ./a.out one two three
0
Segmentation fault (core dumped)
$

Any idea where my fault could be ? I am using a Ubuntu 20.04 VM


回答1:


This looks correct for a minimal _start: but you put it inside a non-naked C function. Compiler-generated code will run, e.g. push %rbp / mov %rsp, %rbp, before execution enters before the asm statement. To see this, look at gcc -S output, or single-step in a debugger such as GDB.

Put your asm statement at global scope (like in How Get arguments value using inline assembly in C without Glibc?) or use __attribute__((naked)) on your _start(). Note that _start isn't really a function

As a rule, never use GNU C Basic asm statements in a non-naked function. Although you might get this to work with -O3 because that would imply -fomit-frame-pointer so the stack would still be pointing at argc and argv when your code ran.

A dynamically linked executable on GNU/Linux will run libc startup code from dynamic linker hooks, so you actually can use printf from _start without manually calling those init functions. Unlike if this was statically linked.

However, your main tries to return to your _start, but you don't show _start calling exit. You should call exit instead of making an _exit system call directly, to make sure stdio buffers get flushed even if output is redirected to a file (making stdout full buffered). Falling off the end of _start would be bad, crashing or getting into an infinite loop depending on what execution falls in to.



来源:https://stackoverflow.com/questions/65169694/linux-getting-terminal-arguments-from-start-not-working-with-inline-assembly-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!