C 系统调用()不能接受空指针

C syscall() cannot accept void pointers

我正在研究一种用 go 编写的动态语言。我正在使用 C 来允许这种语言访问系统调用(至少 linux)。 C 的 any 类型是 void*,所以我认为我可以将它们传递到系统调用中。我使用一些看起来像这样的代码进行了测试:

#include <stdio.h>
#include <unistd.h>

static inline long int vpsyscall(void* a0, void* a1, void* a2, void* a3) {
    return syscall(*((int*)a0), a1, a2, a3);
}

int main() {
    int a_ = 1;
    void* a = &a_;
    int b_ = 1;
    void* b = &b_;
    char* c_ = "hello\n";
    void* c = &c_;
    int d_ = 6;
    void* d = &d_;
    long int ret = tusksyscall(a, b, c, d);
    printf("%ld\n", ret);
}

我希望这段代码应该输出

hello
0

到控制台。

相反,我得到

-1

这(至少据我所知)意味着错误。

奇怪的是,当我传递 1 个参数(斧头)时,它起作用了

int _ax = 39;
void* ax = &_ax;
long int ret = vpsyscall(ax, 0, 0, 0);
printf("%ld\n", ret);

它给了我想要的输出(在本例中,只是 pid)。那么,这里发生了什么,我如何将 void 指针传递给系统调用(如果有的话)?

Linux 系统调用接口只接受指针或与指针大小相同且可以安全地转换为整数的值。但是您没有传递此类对象,而是将指针传递给它们。因此,例如,不是要求 OS 写入文件描述符 1,而是要求它写入文件描述符 0x7fffdeadbeef 或任何局部变量的地址 b_是。显然这不会成功。

您需要转换而不是使用 & 运算符获取地址。

您也可以使用 int 类型的第一个参数,因为您知道它将永远如此。

尝试


static inline long int vpsyscall(int a0, void* a1, void* a2, void* a3) {
    return syscall(a0, a1, a2, a3);
}


int main() {
    vpsyscall(1, (void *)1, "hello", (void *)6);
}

我认为您误以为 void * 是“任何”类型。它可以是任何对象的指针,但不能与该对象互换。要取回对象,您必须将指针转换为对象的类型并取消引用它。这就是您对 vpsyscall 的第一个参数所做的,这就是它起作用的原因,即使它不必要地复杂。