我正在linux 64bit中构建没有glibc的简单应用程序。 但我不知道如何得到论据。
我用Google搜索,我发现RDI是argc,RSI是argv。但它没有奏效。
当_start函数使用gdb启动时我看到了寄存器,但RDI和RSI都是0x0。 我也用最简单的装配应用进行了测试,但结果是一样的。 RDI和RSI是0x0。我相信argc不应该是0x0,即使我没有传递任何参数来编程。
_start:
jmp $
这是我尝试过的C代码:
//Print Hello world WITHOUT standard library
//ONLY WITH SYSTEM CALL
#define ReadRdi(To) asm("movq %%rdi,%0" : "=r"(To));
#define ReadRsi(To) asm("movq %%rsi,%0" : "=r"(To));
void __Print(const char *str);
void __Exit();
void Test(const char *a){
long aL;
ReadRdi(aL);
char *aC = (int) aL;
__Print("Test argument: ");
__Print(aC);
__Print("\n");
}
void _start() {
long argcL;
long argvL;
ReadRdi(argcL);
ReadRsi(argvL);
int argc = (int) argcL;
char **argv = (char **) argvL;
__Print("Arguments: ");
for(int i = 0; i < argc; i ++) {
__Print(argv[i]);
__Print(", ");
}
__Print("\n");
Test("Hello, world!");
__Exit();
}
结果是:
Arguments:
Test argument: Hello, world!
我使用gdb检查了堆栈(RBP~RSP中的内存值),但似乎什么都没有。
我尝试过更改
void _start() {
long argcL;
long argvL;
ReadRdi(argcL);
ReadRsi(argvL);
int argc = (int) argcL;
char **argv = (char **) argvL;
__Print("Arguments: ");
到
void _start(int argc, char **argv) {
__Print("Arguments: ");
但我仍然看不到任何参数输出。
__ Print打印消息(使用sys_write系统调用),__ Exit退出程序(使用sys_exit系统调用)。
Print.asm:
section .text
global __Print
__Print:
mov rdx, 0
push rdi
jmp .count
.count:
add rdx, 1
add rdi, 1
cmp byte[rdi], 0
jne .count
.print:
pop rdi
mov rcx, rdi ;message to write
mov rbx, 1 ;file descriptor (stdout)
mov rax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
ret
Exit.asm:
section .text
global __Exit
__Exit:
mov rax,1 ;system call number (sys_exit)
int 0x80
ADD:我用这个命令链接:
gcc -o sysHello Exit.o Print.o sysHello.o -nostdlib -nodefaultlibs -g
答案 0 :(得分:1)
最简单的方法是在asm中编写_start
,然后使用标准调用约定调用C函数。
请参阅x86 wiki以获取ABI文档的链接,该文档描述了在流程启动时查找所有内容的位置。 (或者使用Ian评论中的链接)。
将_start
写为C函数需要内联asm,因为没有标准方法告诉编译器argc
是返回地址通常所在的位置。所以直接在asm中编写它并且在将args放入寄存器中以获得正常的调用约定之后就更容易了{.1}}。
我用于使用perf计数器测试事物的asm程序的片段:
call main
通过测试cmp dword [rsp], 2
jg addrmode_lat_3comp ; argc > 2 ; $(seq 2)
jge addrmode_lat_1comp ; argc >= 2 ; $(seq 1)
jmp loadlat_1comp ; argc < 2 ; $(seq 0)
,它会跳转到三个循环中的一个,具体取决于我是以2,1还是没有args运行它。它使用NASM语法。