2011-10-17 49 views
3

描述:C++汇编静态变量和共享对象

一个。类X包含一个静态私有数据成员ptr和静态公共函数成员getptr()/ setptr()。
在X.cpp中,ptr被设置为NULL。

b。 libXYZ.so(共享对象)包含类X的对象(即libXYZ.so包含X.o)。

c。 libVWX.so(共享对象)包含X类的对象(即libVWX.so包含X.o)。 d)。可执行A.EXE包含X.cpp作为翻译单元部分,最后连接到libXYZ.so,libVWX.so

PS:
1.有参与任何类的没有用户的命名空间。
2.库和可执行文件还包含许多其他类。
3.没有dlopen()已经完成。所有的库在编译时使用-L和-l标志进行链接。

问题陈述:

  1. 当编译,并与其他库(即libXYZ.so和libVWX.so)连接a.exe的,我期待一个链接错误(冲突/相同的次数符号多次),但没有得到一个。

  2. 当在执行程序 - 行为是SUSE Linux的10和HP-UX 11 IA64奇怪。
    在Linux中,当执行流被推送到不同库中的所有对象时,效果仅在X的一个副本中注册。
    在HPUX中,当执行流被推送到不同库中的所有对象时,效果为在3个不同的充X(2属于每个库和1用于可执行)

PS副本注册:在运行节目期间我的意思是,该流程也传递thourgh属于A.EXE,libXYZ.so多个对象和libVWX.so),其与静态指针交互属于X.

问:

  • 期待链接错误不正确?由于两个编译器默默地通过了编译,可能会有一个标准规则来处理这种类型的场景,而我错过了。如果是这样,请让我知道一样。
  • 如何(在HPUX GCC在Linux和ACC)编译器决定X的多少副本保留在最终的可执行文件,并在这样的情况下是指他们。
  • gcc和aCC是否支持任何标志,这会在这种情况下警告/停止编译给用户?

感谢您的帮助提前。

回答

0

该函数是“公共静态”,所以我假设它是OOP-意思是“静态”(不需要实例) ,而不是C的静态含义(文件静态;本地编译单元)。因此这些功能是外部的。

现在在Linux中,您有明确的权利来覆盖库符号,无论是使用其他库还是可执行文件。库中的所有外部符号都使用全局偏移量表来解析,即使库实际上定义了它自己。尽管可执行文件中定义的函数通常不会像这样解析,但链接器注意到符号将从库中到达符号表,并将引用放置在可执行文件定义的引用中。因此,如果您生成了可执行文件,库会看到在可执行文件中定义的符号。

这是一个显式的功能,可以让您执行诸如替换内存分配函数或打包文件系统操作等功能。HP-UX可能没有此功能,因此每个库最终都会调用它自己的实现,而其他任何具有未定义符号的对象都会看到其中一个。

+0

你的答案看起来是最合乎逻辑的。所以已经授予你积分。唯一值得一提的问题是 - 有没有办法在链接时发现这些问题 - 链接器会在哪里发出错误?如果您知道,请让我知道。 –

+0

@kumar_m_kiran:不幸的是它是系统特定的。 ELF链接器将声明两个.o文件中的符号之间的冲突,除非这些符号很弱(在C++内联方法和模板实例较弱或者可以使用__attribute__),并且不会声明与库中的符号(按设计)冲突。另一方面,Windows将声明与任何符号的冲突,除非用选项覆盖,甚至共享库仍然会调用它们自己的定义,否则这是致命的。 –

1

我不太确定我是否完全理解了这种情况。但是,在Linux下加载动态对象(以及其他的 Unices)的默认行为是使库中的所有符号可用,并且仅使用 第一次遇到。因此,如果您同时包含和libVWX.so 包含符号X::ourData,它不是错误;如果你将它们加载到 那个订单中,libVWX.so将使用, 而不是它自己的X::ourData。从逻辑上讲,这很像头文件中的模板定义 :编译器偶然选择一个,如果任何定义与所有其他定义不同,则为 未定义的行为。通过将标志RTLD_LOCAL传递给dlopen可以覆盖此行为 。

至于你的问题:

  • 的连接仅仅是实现(当系统加载库隐含您获取)的dlopen的默认行为。因此,没有错误(但是,如果任何定义不相同,那么未定义行为的逻辑等价物就不相同)。

  • 编译器没有决定。当加载.so时会作出决定,具体取决于您在致电dlopen时是否指定了RTLD_GLOBALRTLD_LOCAL。当运行时隐式地调用dlopen来解决依赖关系时,如果在加载主可执行文件时发生这种情况,它将使用RTLD_GLOBAL,以及当依赖项来自库时曾用于加载库的内容。 (这意味着,当然,前提是RTLD_GLOBAL将传播,直到调用dlopen明确。)

+0

感谢您的初始响应,但是,“因此,如果您同时使用libXYZ.so和libVWX.so .....”并不能解释为什么Linux和HPUX中的行为不同。在Linux中,它符合你的解释。但在HP中,看起来像mySO :: X :: ourData用于设置X的值。 –

+0

@kumar_m_kiran我不熟悉HP-UX,所以我不能说。 Posix确实说过,如果RTLD_GLOBAL和RTLD_LOCAL都没有给出,那么缺省值就是实现定义的。我描述的行为与我所知道的两个平台的行为相对应:Linux和Solaris。 –

0

有beetween“外部的”符号的差(这是在C++缺省值)和“共享libary外部”。默认情况下,符号只是“extern”,这意味着一个“链接单元”的范围,例如一个可执行文件或一个库。 所以预期的行为将是:没有编译器错误,并且每个模块都有自己的副本。 这会导致内联编译等问题......等等...... 要声明符号“共享库extern”,您必须使用“.def”文件或编译器声明。 例如在visual C++中,这将是“_ declspec(dllexport)”和“ _declspec(dllimport)”。 我不知道gcc目前的声明,但我确信有人会这样做:-)

+0

在Windows中,它就像那样(编译器错误部分除外;除非用'/ force'覆盖,否则它是链接器错误)。但是Linux(ELF)的行为有所不同。它默认导出符号(如果需要,可以显式隐藏它们),并且总是导入它所导出的所有符号(当然也可以被显式覆盖),所以如果多个对象定义相同的符号,它们总是最终使用相同的符号定义。 –