简体   繁体   English

C syscall() 不能接受空指针

[英]C syscall() cannot accept void pointers

I am working on a dynamic language written in go.我正在研究一种用 go 编写的动态语言。 I am using C to allow this language to access syscalls (for linux at least).我正在使用 C 来允许这种语言访问系统调用(至少对于 linux)。 C's any type is a void* , so I thought that I can pass them into a syscall. C 的any类型都是void* ,所以我认为我可以将它们传递给系统调用。 I tested using some code which looks like:我使用一些看起来像这样的代码进行了测试:

#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);
}

I expect that this code should output我希望这段代码应该输出

hello
0

to the console.到控制台。

Instead, I get相反,我得到

-1

which (at least to my knowledge) means error.这(至少据我所知)意味着错误。

Strangely, when I pass 1 argument (the ax), it works奇怪的是,当我传递 1 个参数(斧头)时,它起作用了

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

It gives me the desired output (in this case, just the pid).它给了我想要的输出(在这种情况下,只是 pid)。 So, whats going on here, and how can I pass void pointers to a syscall (if there is any way)?那么,这里发生了什么,我如何将 void 指针传递给系统调用(如果有任何方法)?

The Linux system call interface only takes values which are either pointers, or integers that are the same size as a pointer and can be safely cast to them. Linux 系统调用接口只接受指针或与指针大小相同的整数,并且可以安全地转换为这些值。 But you are not passing such objects, you are passing pointers to them.但你不及格这样的对象,你传递指针他们。 So for instance, instead of asking the OS to write to file descriptor 1, you're asking it to write to file descriptor 0x7fffdeadbeef or whatever the address of the local variable b_ happens to be.因此,例如,不是要求操作系统写入文件描述符 1,而是要求它写入文件描述符0x7fffdeadbeef或任何局部变量b_的地址。 Clearly this will not succeed.显然这不会成功。

You need to cast instead of taking the address with the & operator.您需要强制转换而不是使用&运算符获取地址。

You also might as well make the first argument of type int since you know that's what it will always be.您也可以使用int类型的第一个参数,因为您知道它将始终如此。

Try尝试


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);
}

I think you're misled by thinking of void * as an "any" type.我认为您将void *视为“任何”类型会误导您。 It can be a pointer to any object, but it's not interchangeable with that object.它可以是指向任何对象的指针,但不能与该对象互换。 To get the object back, you have to cast your pointer to the type of the object and dereference it.要取回对象,您必须将指针强制转换为对象的类型并取消引用它。 That's what you did with the first argument to your vpsyscall , which is why it worked, even though it was unnecessarily complicated.这就是你对vpsyscall的第一个参数vpsyscall ,这就是它工作的原因,即使它不必要地复杂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM