Linux 从 _start 获取终端参数无法在 C 中使用内联汇编
Linux getting terminal arguments from _start not working with inline assembly in C
我正在尝试使用内联汇编编写自己的 _start 函数。但是当我尝试从堆栈(%rsp 和 %rsp + 8)读取 argc 和 argv 时,我得到了错误的值。我不知道我做错了什么。
#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"
...
航站楼:
$ gcc test.c -nostartfiles
$ ./a.out one two three
0
Segmentation fault (core dumped)
$
知道我的错在哪里吗?
我正在使用 Ubuntu 20.04 VM
对于最小 _start:
这看起来是正确的,但您将它放在非 naked
C 函数中。编译器生成的代码将 运行,例如push %rbp
/ mov %rsp, %rbp
,执行前进入asm语句之前。要查看此内容,请查看 gcc -S
输出,或在 GDB 等调试器中单步执行。
将您的 asm 语句放在全局范围内(如在 How Get arguments value using inline assembly in C without Glibc? 中)或在您的 _start()
上使用 __attribute__((naked))
。请注意 _start
并不是真正的函数
作为规则,永远不要在非裸函数中使用 GNU C Basic asm 语句。尽管您可能会使用 -O3
来使用它,因为这意味着 -fomit-frame-pointer
所以当您的代码 运行.
时,堆栈仍将指向 argc 和 argv
GNU/Linux 上的动态链接可执行文件将从动态链接器挂钩 运行 libc 启动代码,因此您实际上 可以 使用 printf
来自_start
无需手动调用那些初始化函数。与静态链接不同。
然而,您的 main
试图 return 到您的 _start
,但您没有显示 _start
呼叫 exit
。您 应该 调用 exit
而不是直接进行 _exit 系统调用,以确保即使输出被重定向到文件(使 stdout 完全缓冲)也能刷新 stdio 缓冲区。从 _start
的末尾掉下来会很糟糕,崩溃或进入无限循环取决于执行的结果。
我正在尝试使用内联汇编编写自己的 _start 函数。但是当我尝试从堆栈(%rsp 和 %rsp + 8)读取 argc 和 argv 时,我得到了错误的值。我不知道我做错了什么。
#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"
...
航站楼:
$ gcc test.c -nostartfiles
$ ./a.out one two three
0
Segmentation fault (core dumped)
$
知道我的错在哪里吗? 我正在使用 Ubuntu 20.04 VM
对于最小 _start:
这看起来是正确的,但您将它放在非 naked
C 函数中。编译器生成的代码将 运行,例如push %rbp
/ mov %rsp, %rbp
,执行前进入asm语句之前。要查看此内容,请查看 gcc -S
输出,或在 GDB 等调试器中单步执行。
将您的 asm 语句放在全局范围内(如在 How Get arguments value using inline assembly in C without Glibc? 中)或在您的 _start()
上使用 __attribute__((naked))
。请注意 _start
并不是真正的函数
作为规则,永远不要在非裸函数中使用 GNU C Basic asm 语句。尽管您可能会使用 -O3
来使用它,因为这意味着 -fomit-frame-pointer
所以当您的代码 运行.
GNU/Linux 上的动态链接可执行文件将从动态链接器挂钩 运行 libc 启动代码,因此您实际上 可以 使用 printf
来自_start
无需手动调用那些初始化函数。与静态链接不同。
然而,您的 main
试图 return 到您的 _start
,但您没有显示 _start
呼叫 exit
。您 应该 调用 exit
而不是直接进行 _exit 系统调用,以确保即使输出被重定向到文件(使 stdout 完全缓冲)也能刷新 stdio 缓冲区。从 _start
的末尾掉下来会很糟糕,崩溃或进入无限循环取决于执行的结果。