当前位置: 首页 > 知识库问答 >
问题:

如何读取函数中_start参数?

陆洛城
2023-03-14

我正在linux 64bit中构建没有glibc的简单应用程序。但是我不知道如何获取参数。

我谷歌了一下,发现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: ");

但是我仍然看不到任何参数输出。

__打印打印消息(使用sys_write系统调用),__Exit退出程序(使用sys _Exit系统调用)。

Print.asm:

secthtml" target="_blank">ion     .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

退出asm:

section     .text
global      __Exit
__Exit:
    mov rax,1                               ;system call number (sys_exit)
    int 0x80

添加:我用这个命令链接:

gcc -o sysHello Exit.o Print.o sysHello.o -nostdlib -nodefaultlibs -g

共有1个答案

傅阳炎
2023-03-14

最简单的方法是在asm中编写< code>_start,并让它使用标准的调用约定来调用您的C函数。

有关ABI文档的链接,请参阅x86wiki,该文档描述了在流程启动时在何处查找所有内容。(或者使用Ian评论中的链接)。

_start编写为C函数需要内联asm,因为没有标准的方法来告诉编译器argc是返回地址的正常位置。因此,只需直接在asm中编写它,并在将参数放入常规调用约定的寄存器中之后让它调用main就更容易了。

我用于测试性能计数器的asm程序的一个片段:

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)

通过测试< code>argc,它跳转到三个循环之一,这取决于我是用2个、1个还是没有参数来运行它。它使用NASM语法。

 类似资料:
  • 问题内容: 我正在尝试创建一个程序以仅在屏幕上编写参数。我创建了一些程序来获取C函数参数,或者使用C将参数发送给我的asm程序。有没有办法只使用汇编器来获取程序参数 例如: 我正在使用(Gnu汇编器) 通常我使用 因为esp是程序/函数调用指针,但是在纯asm中,它没有获取命令行参数。 有没有办法做到这一点? 我用谷歌搜索,但是我找不到很多信息 问题答案: 在Linux上,熟悉的C语言和变量始终由

  • jna 中 structure 结构体怎么读取, 在回调函数中 我收到对方返回一个 pointer 是海康的sdk NET_DVR_SetDVRMessageCallBack_v50 的回调函数 有个 pAlarmInfo:Pointer 类型, 想接收为 NET_DVR_ACS_ALARM_INFO 类型, 要怎么做 我试过这样读取, 但没有讲到到

  • 我正在使用AWS Lambda+API网关+无服务器(Python)。太神奇了!

  • 问题内容: 我想使用串行com端口进行通信,并且每次调用read函数调用时都想实现超时。 编辑: 我正在使用Linux OS。如何使用选择函数调用实现? 问题答案: select()有5个参数,首先是最高的文件描述符+ 1,然后是fd_set用于读取,一个用于写入,一个用于异常。最后一个参数是struct timeval,用于超时。错误时返回-1,超时时返回0或设置的集合中文件描述符的数量。

  • 问题内容: Python程序员可以通过哪些方式做到这一点? 问题答案: 标准库中的规范解决方案是: 这是一个例子: 任意顺序的多个选项。 短期和长期选择。 默认值。 生成使用帮助消息。

  • 我正在尝试从HTML中读取post请求参数。我可以使用以下JavaScript代码读取get请求参数。 但对post请求不起作用。有人能告诉我如何使用JavaScript读取HTML中的post请求参数值吗?