【问题标题】:C sockets <error reading variable: Cannot access memory at address 0xfffffffffffffffc>C 套接字 <错误读取变量:无法访问地址 0xfffffffffffffffc 处的内存>
【发布时间】:2023-03-12 21:40:02
【问题描述】:

以下 C 程序调用 select() 以获取在套接字缓冲区中有数据的客户端套接字列表(使用 UNIX 域数据报套接字)。它在调用 NASM 程序时需要四个参数。参数 fds_array[] 是在 NASM 中创建并传递给程序的 3 元素整数数组。

int select_clientsockets(int nfds, fd_set rfds, int fds_array[], int fd_count){

    int fds_ready;
    int abc;
    fd_count = 3;

    FD_ZERO(&rfds);
    FD_SET(0,&rfds);

    fds_ready = select(3, &rfds, NULL, NULL, 0);

    for (int i = 0; i < fd_count; i++){

        fds_array[i] = 0;

        if (FD_ISSET(i, &rfds)) {
            fds_array[i] = 1; }
    }

    for (int i = 0; i < fd_count; i++){
        abc = fds_array[i];
        printf("Value of array at %d, is %d\n", i, abc );
    }

    return 0;
}

数据从 NASM 传入 rdi、rsi、rdx 和 rcx。 :

mov rdi,7 ; range of fd #s
lea rsi,[socket_client_fds]
lea rdx,[fds_ready]
mov rcx,3 ; number of open client sockets
call [rel select_clientsockets wrt ..got]

正如所写,程序挂起。当我使用 gdb 逐步完成它时,它会正确地进行计算,并且 fds_array 中的值与预期的一样。但是在返回行(返回 0),gdb 会报告这个:

0x00007ffff720cfed in select_clientsockets (
    nfds=<error reading variable: Cannot access memory at address   0xfffffffffffffffc>, rfds=<error reading variable: Cannot access memory     at address 0x10>,
    fds_array=<error reading variable: Cannot access memory at address  0xfffffffffffffff0>,
    fd_count=<error reading variable: Cannot access memory at address   0xffffffffffffffec>) at POSIX_Datagram_Socket.c:139

所以它说变量 nfds、rfds 和 fds_array 无法访问。但我刚刚完成了它,一切都是正确的。

我的研究发现了关于该 gdb 错误消息的许多 Stack Overflow 问题,但它们都是特定于事实的,我没有找到任何符合这些事实的问题。

感谢您提供有关如何在退出时修复此错误的任何想法。

【问题讨论】:

  • 贴出调用select_clientsockets的代码。但是 C 函数中有一些非常可疑的东西——nfdsrfdsfd_count 参数甚至可以做什么?请记住,fs_set 是一种结构类型,因此它在 x86_64 中进入堆栈,但其他参数进入寄存器。
  • 我刚刚更新了上面的 NASM 代码以显示调用。这就是进行调用的所有 NASM 代码。 nfds 是文件描述符的数量 (3);它作为 7 传递,因为 fd 编号是 5、6 和 7,但我在代码中将其更改为 3; rfds 是 fd_set。 socket_client_fds 是一个 3 元素数组,其中包含每个客户端套接字的文件描述符。
  • 看起来问题可能是我没有正确处理 fd_set - 文件描述符的 3 元素数组不是 select() 所要求的。

标签: c linux sockets nasm


【解决方案1】:

让我们看看这个调用......

mov rdi,7 ; range of fd #s
lea rsi,[socket_client_fds]
lea rdx,[fds_ready]
mov rcx,3 ; number of open client sockets
call [rel select_clientsockets wrt ..got]

在 System V AMD64 ABI 中,参数将被传入:

  • rdi - ndfs
  • rsi - fds_array
  • rsp..rsp+127 - rfds
  • rdx - fd_count

看起来你正在传递rfds,就好像它是一个指针。它不是。它进入堆栈。

如果这是 Windows,它作为指针传递。但是,听起来您没有使用 Windows,因为您提到了 Unix 域套接字(尽管 AF_UNIX 实际上在 Windows 上可用)。

如果您需要帮助从程序集中调用 C 函数,只需使用 Godbolt

【讨论】:

  • 是的,Linux。我现在可以看到 rdfs 是一个结构,因此它的传递方式会有所不同。它也可以在 NASM 中创建为结构并通过指针传递(在其他情况下我已经这样做了)。谢谢你的回答。
  • 另一个问题——如果我在堆栈上传递结构,那么在调用之后为结构放下一些堆栈空间并展开,而不是使用 rsp+127 不是更好吗?我问是因为这个程序在堆栈上存储了其他变量。
猜你喜欢
  • 1970-01-01
  • 2016-03-07
  • 1970-01-01
  • 2017-08-28
  • 1970-01-01
  • 2019-03-26
  • 2018-09-08
  • 2013-02-18
  • 1970-01-01
相关资源
最近更新 更多