c - 如何在没有 Glibc 的情况下使用 C 中的内联汇编获取参数值?
问题描述
如何在没有 Glibc 的情况下使用 C 中的内联汇编获取参数值?
我需要此代码用于Linux
架构x86_64
和i386
. 如果您知道MAC OS X
or Windows
,也提交并请指导。
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
和
#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。所以这段代码是错误的!请帮忙。
解决方案
如注释中所指定,argc
并argv
在堆栈上提供,因此即使使用内联汇编,您也不能使用常规 C 函数来获取它们,因为编译器将触摸堆栈指针以分配局部变量,设置堆栈框架和 co .; 因此,_start
必须用汇编编写,就像在 glibc ( x86 ; x86_64 ) 中所做的那样。根据常规调用约定,可以编写一个小存根来抓取这些内容并将其转发到您的“真实”C 入口点。
这是一个程序的最小示例(适用于 x86 和 x86_64),它读取argc
和argv
,在标准输出上打印所有值(由换行符分隔)并使用状态码argv
退出;argc
它可以用通常的方式编译gcc -nostdlib
(并-static
确保ld.so
不涉及;并不是说它在这里造成任何伤害)。
#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 文件中的注释中提取。
推荐阅读
- xml - 在 XSLT 中使用 foreach 添加属性值
- java - wget url 用于查找特定的 java 版本
- python-3.x - 从数组对象中查找平均值和最小值 - Python
- posix - 将 Windows 库调用转换为 POSIX 以实现 Linux 兼容性
- firebase - Vue Vuex Firebase Auth 电子邮件登录并更新用户名
- ios - 如何使用 UISearchBar 搜索文本和图像
- html - 跨度和边界之间需要空间
- google-bigquery - 如何将过去几天的数据从 Firebase 重新加载到 BigQuery?
- jquery - 函数 close_window() { 如果
- ios - 启动时奇怪的 Facebook 崩溃