extern "C" C++ 程序中的外部变量寻求作为 class 变量..如何声明它?
extern "C" extern variable in C++ program sought as a class variable.. how to declare it?
我有下面的代码。它是动态共享库的一部分,由 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;
}
因为变量host_virt_offset是在qemu(一个C程序)中定义的,所以我认为它可以在这个共享库中使用没有问题。但是当我 运行 它时,错误发生了,当我使用调试器检查它时,我发现代码正在寻找 Driver::host_virt_offset
而不是全局(和外部)变量 host_virt_offset
。我通过下面那条线附近知道这一点。
(gdb) print host_virt_offset
Missing ELF symbol "AXPU::host_virt_offset".
我尝试在 a、b 行中使用 ::host_virt_offset
,但它无法编译。我应该如何声明和使用变量host_virt_offset?
ADD : (我有一段时间无法连接到 Whosebug) 我制作了一个可重现的程序。在这里使用我使用的方法可以正常工作。所以还有别的东西。 '
<< 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;
}
<> <-- 共享库
#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();
}
}
<< 结果 >>
$ 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
extern "C"
在声明变量时没有区别,它只对函数有影响。
原因是C++中的函数可以重叠,而变量不能。
例如:
#include <iostream>
using namespace std;
extern "C" {
int n1 = 1;
}
int n2 =2;
int main()
{
cout<<n1<<endl<<n2<<endl;
return 0;
}
在上面的代码中,n1
和n2
访问相同。
我就是这样解决的。
我在 class Driver
中添加了变量 host_virt_offset
,这与 qemu 设置的变量 host_virt_offset
不同。然后我将 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 ..
}
原来的代码应该改成下面这样。
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;
}
现在 host_virt_offset 值在 class 成员函数中是正确的并且 gdb 命令中的 print host_virt_offset
不会抱怨并显示正确的值(我认为 gdb 正在显示class 此代码点的变量)。
此代码向 qemu 客户物理地址添加一些偏移量以将其转换为主机虚拟地址(即,qemu 程序域地址)。 args_ptr 本身是来宾物理地址,所以我也必须将偏移量提供给该值。 (没有它,段错误会像以前一样出现。)
我有下面的代码。它是动态共享库的一部分,由 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;
}
因为变量host_virt_offset是在qemu(一个C程序)中定义的,所以我认为它可以在这个共享库中使用没有问题。但是当我 运行 它时,错误发生了,当我使用调试器检查它时,我发现代码正在寻找 Driver::host_virt_offset
而不是全局(和外部)变量 host_virt_offset
。我通过下面那条线附近知道这一点。
(gdb) print host_virt_offset
Missing ELF symbol "AXPU::host_virt_offset".
我尝试在 a、b 行中使用 ::host_virt_offset
,但它无法编译。我应该如何声明和使用变量host_virt_offset?
ADD : (我有一段时间无法连接到 Whosebug) 我制作了一个可重现的程序。在这里使用我使用的方法可以正常工作。所以还有别的东西。 '
<< 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;
}
<
#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();
}
}
<< 结果 >>
$ 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
extern "C"
在声明变量时没有区别,它只对函数有影响。
原因是C++中的函数可以重叠,而变量不能。
例如:
#include <iostream>
using namespace std;
extern "C" {
int n1 = 1;
}
int n2 =2;
int main()
{
cout<<n1<<endl<<n2<<endl;
return 0;
}
在上面的代码中,n1
和n2
访问相同。
我就是这样解决的。
我在 class Driver
中添加了变量 host_virt_offset
,这与 qemu 设置的变量 host_virt_offset
不同。然后我将 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 ..
}
原来的代码应该改成下面这样。
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;
}
现在 host_virt_offset 值在 class 成员函数中是正确的并且 gdb 命令中的 print host_virt_offset
不会抱怨并显示正确的值(我认为 gdb 正在显示class 此代码点的变量)。
此代码向 qemu 客户物理地址添加一些偏移量以将其转换为主机虚拟地址(即,qemu 程序域地址)。 args_ptr 本身是来宾物理地址,所以我也必须将偏移量提供给该值。 (没有它,段错误会像以前一样出现。)