这是我拥有的一个最小代码示例(我try 运行这个最小示例以确保它重现我看到的问题):

void testfn(void) {
    printf("Hello, world!\n");
}

int main(int argc, char *argv[]) {
    printf("fp: %p\n", &testfn);
    return 0;
}

我得到的输出是fp: 0x0000000000000000,表明我试图打印的函数指针是0.我try 在testfn()上使用CC __attribute__((noinline))属性,得到了相同的结果.

我正在为RISC-V系统进行编译并在QEMU中运行.我认为也许printf()实现有缺陷(尽管它对我来说看起来很好,而且其他指针打印也很好),所以我try 将函数指针转换为无符号的64位int,然后循环那么多次迭代(我认识到这在技术上是JB,但通常在实践中有效,这是一个愚蠢的测试),但循环恰好执行0次迭代:

void __attribute__((noinline)) testfn(void) {
    printf("Hello, world!\n");
}

int main(int argc, char *argv[]) {
    void (*fn)(void) = &testfn;

    printf("Testing printf...\n");
    printf("fp addr: %p\n", &fn);
    fn();

    for (int i = 0; i < (unsigned long long) fn; ++i) {
        printf("Here!\n");
    }

    printf("fp: %p\n", fn);
    return 0;
}

这将产生以下输出:

Testing printf...
fp addr: 0x0000000000003FA8
Hello, world!
fp: 0x0000000000000000

以下是用于编译的命令:riscv64-unknown-elf-gcc -Wall -O0 -fno-omit-frame-pointer -ggdb -gdwarf-2 -MD -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie -c -o user/rkttest.o user/rkttest.c

这是我用来运行QEMU的命令; qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -global virtio-mmio.force-legacy=false -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0.

在我看来,函数指针总是零,除非我试图将其称为函数.在我看来,这就像是一个编译器错误或我的环境中发生的一些奇怪的事情,但我想我应该把它放在Stack OverFlow上.我是不是错过了什么?

推荐答案

看来系统实际上正在将代码部分放置在地址0x 0,而编译器则将该函数放置在代码部分的开头.对于系统的一部分来说,这确实是一个糟糕的主意.地址0x 0,ever处不应有任何内容.

以下代码:

static void __attribute__((noinline)) testfn(void) {
    printf("Hello, world!\n");
}

static void __attribute__((noinline)) testfn2(void) {
    printf("Hello, world!\n");
}

int main(int argc, char *argv[]) {
    printf("fp: %p\n", (void *) &testfn);
    printf("fp: %p\n", (void *) &testfn2);

    return 0;
}

产生以下输出:

fp: 0x000000000000001A
fp: 0x0000000000000000

哦天啊.🤦‍♂️

Edit: Okay, maybe saying "nothing should be at address 0x0, ever" isn't necessarily true (counterpoint: systems without virtual addressing). But for systems with virtual addressing, I still believe it is a really bad idea to map that page, if only to avoid issues arising from bad assumptions.

C++相关问答推荐

理解C中的指针定义

C限制限定符是否可以通过指针传递?

如果包含路径不存在,我的编译器可以被配置为出错吗?(GCC、MSVC)

为什么删除CAP_DAC_OVERRIDE后创建文件失败?

用C宏替换strncMP函数中的参数

如何使用指向 struct 数组的指针并访问数组中特定索引处的 struct

SSH会话出现意外状态

将返回的char*设置为S在函数中定义的字符串文字可能会产生什么问题?

如何将另一个数组添加到集合中,特别是字符串?

致命错误:ASM/rwan ce.h:没有这样的文件或目录.符号链接还不够

类型定义 struct 与简单的类型定义 struct

不使用任何预定义的C函数进行逐位运算

对于STM32微控制器,全局偏移表.get和.Got.plt必须为零初始化

Valgrind用net_pton()抱怨

从CentOS 7到Raspberry PI 2B的交叉编译-无法让LIBC和System Include标头一起工作

为什么这个代码的最后一次迭代不能正常工作?

C中2个数字的加法 - 简单的人类方法

如何找出C中分配在堆上的数组的大小?

如何为avr atmega32微控制器构建C代码,通过光电二极管捕获光强度并通过串行通信传输数据

从管道读取数据时丢失