简体   繁体   English

外部“C” C++ 程序中的外部变量作为 class 变量.. 如何声明它?

[英]extern "C" extern variable in C++ program sought as a class variable.. how to declare it?

I have a code below.我在下面有一个代码。 It is part of a dynamic shared library which is loaded by qemu program (a C program) using dlopen.它是由 qemu 程序(一个 C 程序)使用 dlopen 加载的动态共享库的一部分。

extern "C" {
extern uint64_t host_virt_offset;
}

int Driver::CallSetBareMetalMode( uint64_t * args_ptr)
{
    dbg_enter();
    
    (... some codes ..)

    baremetal_axpu_es   = (struct es_t      *)(args_ptr[0] + host_virt_offset);   // line a
    baremetal_axpu_regs = (struct reg_csr_t *)(args_ptr[1] + host_virt_offset);   // line b

    dbg_leave();
    return 0;
}

Because the variable host_virt_offset is defined in qemu (a C program), I thought it can be used inside this shared library with no problem.因为变量host_virt_offset是在qemu(一个C程序)中定义的,所以我认为可以在这个共享库里面使用没有问题。 But when I run it, error occurs, and when I examined it using debugger, I found the code is looking for Driver::host_virt_offset instead of the global (and extern) variable host_virt_offset .但是当我运行它时,会发生错误,当我使用调试器检查它时,我发现代码正在寻找Driver::host_virt_offset而不是全局(和外部)变量host_virt_offset I know this through below near that line.我通过该线附近的下方知道这一点。

(gdb) print host_virt_offset
Missing ELF symbol "AXPU::host_virt_offset".

I tried using ::host_virt_offset in lines a,b instead but it doesn't compile.我尝试在 a,b 行中使用::host_virt_offset ,但它没有编译。 How should I declare and use the variable host_virt_offset?我应该如何声明和使用变量 host_virt_offset?

ADD: (I couldn't connect to stackoverflow for a while) I made a reproducible program. ADD:(我有一段时间无法连接到stackoverflow)我制作了一个可重现的程序。 Here it works ok using method I used.在这里使用我使用的方法可以正常工作。 So there is something else.所以还有别的东西。 ' '

<< main.c >> << main.c >>

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

uint64_t var_from_qemu = 0x12345678;

int main(void)
{
    void * dlh = dlopen("./libbar.so", RTLD_NOW);
    if (!dlh) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE); 
    }
    void (*bar)(void) = dlsym(dlh,"bar");
    if (!bar) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE); 
    }
    bar();
    return 0;
}

<<bar.cpp>> <-- shared library <<bar.cpp>> <-- 共享库

#include <stdint.h>
#include <stdio.h>

extern "C" {
extern uint64_t var_from_qemu;
}

class BC;

class BC {
public:
    void bar(void);
    BC();
    ~BC();
};

BC::BC()
{
}

BC::~BC()
{
}

void BC::bar(void)
{
    printf("class function : var_from_qemu = %lx\n", var_from_qemu);
}

extern "C" {
void bar(void)
{
printf("global function : var_from_qemu = %lx\n", var_from_qemu);
BC tmp;
tmp.bar();
}
}

<< result >> <<结果>>

$ g++ bar.cpp -Wall -fpic -shared -g -o libbar.so
$ gcc main.c -o main -g -ldl -rdynamic
$ main
global function : var_from_qemu = 12345678
class function : var_from_qemu = 12345678

The extern "C" makes no difference when declaring variables, it matters only for functions. extern "C"在声明变量时没有区别,它只对函数很重要。 The reason is that functions in C++ can be overlapped but variables can't.原因是 C++ 中的函数可以重叠,但变量不能。

for example:例如:

#include <iostream>
using namespace std;
extern "C" {
    int n1 = 1;
    
}
int n2 =2;
int main()
{
    cout<<n1<<endl<<n2<<endl;
    return 0;
}

In the above code, n1 and n2 are accessed the same.在上面的代码中, n1n2的访问方式相同。

This is how I solved it.这就是我解决它的方法。
I added the variable host_virt_offset in class Driver which is different from the variable host_virt_offset which is set by qemu.我在 class Driver中添加了变量host_virt_offset ,它与 qemu 设置的变量host_virt_offset不同。 And I copied the extern host_virt_offset to the class Driver 's variable host_virt_offset like below.我将 extern host_virt_offset复制到 class Driver的变量host_virt_offset ,如下所示。

extern "C" int some_function_during_the_init(...)
{
... some codes ..
AXPU::Driver *axpu_driver = AXPU::Driver::getInstance();
axpu_driver->host_virt_offset = host_virt_offset;   // copy to the class variable
... some codes .. 
}

And the original code should be changed like below.并且应该像下面这样更改原始代码。

extern "C" {
extern uint64_t host_virt_offset;
}

int Driver::CallSetBareMetalMode( uint64_t * args_ptr)
{
    dbg_enter();
    
    (... some codes ..)

    baremetal_axpu_es   = (struct es_t      *)((args_ptr + host_virt_offset/8)[0] + host_virt_offset);     // line a
    baremetal_axpu_regs = (struct reg_csr_t *)((args_ptr + host_virt_offset/8)[1] + host_virt_offset);     // line b


    dbg_leave();
    return 0;
}

Now the host_virt_offset value is correct inside the class member function and print host_virt_offset in gdb command doesn't complain and shows the correct value(I think the gdb is showing the class variable at this code point). Now the host_virt_offset value is correct inside the class member function and print host_virt_offset in gdb command doesn't complain and shows the correct value(I think the gdb is showing the class variable at this code point).
This code is adding some offset to the qemu guest physical address to convert it to host virtual address (ie, qemu program domain adderess).这段代码向 qemu 客户物理地址添加了一些偏移量,以将其转换为主机虚拟地址(即 qemu 程序域地址)。 The args_ptr itself was guest physical adderss so I had to give the offset to the value too. args_ptr 本身就是来宾物理加法器,所以我也必须将偏移量赋予该值。 (without it, seg-fault will arise as before.) (没有它,seg-fault 会像以前一样出现。)

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

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