首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >即使具有显式可见性,C共享库中的一些C符号也不会导出

即使具有显式可见性,C共享库中的一些C符号也不会导出
EN

Stack Overflow用户
提问于 2019-09-18 13:00:19
回答 1查看 590关注 0票数 3

前言

我正在用C开发一个面向对象的库,它同时针对Linux和Windows。

目前,我正在Linux (Guest)上开发,因为我使用的是clang消毒液。

我是用-fvisibility=hidden构建的,所以我只使用__attribute__((visibility("default")))导出所需的函数。

据我所理解,该属性需要与函数定义一起使用,因此我将其放在源文件中,使头部保持干净。

我的库依赖于一种非常简单的面向对象的方法,它使用了一个struct base,它定义了在内部调用函数指针的vtable

问题

构建共享库成功,而构建测试则不成功。

链接器抱怨对某些函数的未定义引用:

代码语言:javascript
复制
[ 17%] Built target clib
Scanning dependencies of target test_undefined_san
[ 20%] Building C object CMakeFiles/test_undefined_san.dir/test/allocator/test_default_allocator.c.o
[ 23%] Linking C executable test_undefined_san
/usr/bin/ld: /tmp/lto-llvm-b74224.o: in function `test_default_allocator':
<path>/test_default_allocator.c:17: undefined reference to `clib_init'
/usr/bin/ld: <path>/test_default_allocator.c:21: undefined reference to `clib_allocate'
/usr/bin/ld: <path>/test_default_allocator.c:23: undefined reference to `clib_deallocate'
/usr/bin/ld: <path>/test_default_allocator.c:26: undefined reference to `clib_finalize'
clang-8: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [CMakeFiles/test_undefined_san.dir/build.make:160: test_undefined_san] Error 1
make[1]: *** [CMakeFiles/Makefile2:328: CMakeFiles/test_undefined_san.dir/all] Error 2
make: *** [Makefile:95: all] Error 2
The terminal process terminated with exit code: 2

事实上,这些函数的定义都标记为__attribute__((visibility("default")))

执行nm libname.so会产生有趣的结果。符号不在那里!不隐藏,甚至不存在于物体内!

代码语言:javascript
复制
0000000000001140 T clib_timer_end   <--| other tests, exported correctly
0000000000001110 T clib_timer_start <--| 
                 U clock@@GLIBC_2.2.5
0000000000004028 b completed.7383
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000001040 t deregister_tm_clones
00000000000010b0 t __do_global_dtors_aux
0000000000003df8 t __do_global_dtors_aux_fini_array_entry
0000000000004020 d __dso_handle
0000000000003e00 d _DYNAMIC
0000000000001170 t _fini
0000000000001100 t frame_dummy
0000000000003df0 t __frame_dummy_init_array_entry
00000000000020a8 r __FRAME_END__
0000000000004000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 t _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000001070 t register_tm_clones
0000000000004028 d __TMC_END__

实际代码

头保护,断言和各种无关的东西省略了。

分配器.h\\这是基类

代码语言:javascript
复制
#include <stdbool.h>
#include <stddef.h>

struct clib_allocator;

typedef bool (*clib_alloc_init_t)(struct clib_allocator *);
typedef bool (*clib_alloc_finalize_t)(struct clib_allocator *);
typedef void *(*clib_alloc_allocate_t)(struct clib_allocator *, size_t, size_t);
typedef void (*clib_alloc_deallocate_t)(struct clib_allocator *, void *, size_t, size_t);

struct clib_allocator_vtable
{
    clib_alloc_init_t init;
    clib_alloc_finalize_t finalize;
    clib_alloc_allocate_t allocate;
    clib_alloc_deallocate_t deallocate;
};

struct clib_allocator
{
    struct clib_allocator_vtable vtable;
};

bool clib_init(struct clib_allocator *alloc);
bool clib_finalize(struct clib_allocator *alloc);
void*clib_allocate(struct clib_allocator *alloc, size_t sz, size_t align);
void clib_deallocate(struct clib_allocator *alloc, void *p, size_t sz, size_t align);

分配器.c

代码语言:javascript
复制
// Just calls alloc->vtable.method

#include <clib/allocator/allocator.h>

#define EX __attribute__((visibility("default"))) // just to reduce code

bool EX clib_init(struct clib_allocator *alloc)
{
    return alloc->vtable.init(alloc);
}
bool EX clib_finalize(struct clib_allocator *alloc)
{
    return alloc->vtable.finalize(alloc);
}
void* EX clib_allocate(struct clib_allocator *alloc, size_t sz, size_t align)
{
    return alloc->vtable.allocate(alloc, sz, align);
}
void EX clib_deallocate(struct clib_allocator *alloc, void *p, size_t sz, size_t align)
{
    alloc->vtable.deallocate(alloc, p, sz, align);
}

default_allocator.h =实现分配器

代码语言:javascript
复制
#include <clib/allocator/allocator.h>

struct clib_allocator* clib_get_default_allocator();

default_allocator.c /对齐/自由包装器

代码语言:javascript
复制
// Only clib_get_default_allocator should be exported

#include <clib/allocator/default_allocator.h>

#include <stdlib.h>
#include <assert.h>
#include <threads.h>

static bool nop(struct clib_allocator *CLIB_UNUSED alloc)
{
    return true;
}

static void *aligned_alloc_w(struct clib_allocator *CLIB_UNUSED alloc, size_t sz, size_t align)
{
    return aligned_alloc(align, sz);
}

static void free_w(struct clib_allocator *CLIB_UNUSED alloc, void *p, size_t CLIB_UNUSED sz, size_t CLIB_UNUSED align)
{
    free(p);
}

static once_flag clib_init_default_alloc_flag = ONCE_FLAG_INIT;
static struct clib_allocator clib_default_alloc;

static void clib_init_default_allocator()
{
    clib_default_alloc.vtable.init = nop;
    clib_default_alloc.vtable.finalize = nop;
    clib_default_alloc.vtable.allocate = aligned_alloc_w;
    clib_default_alloc.vtable.deallocate = free_w;
}

#define EX __attribute__((visibility("default"))) // just to reduce code

struct clib_allocator* EX clib_get_default_allocator()
{
    call_once(&clib_init_default_alloc_flag, clib_init_default_allocator);
    return &clib_default_alloc;
}

test_default_allocator.c

代码语言:javascript
复制
#include <cute.h> // test assert library

#include <clib/allocator/default_allocator.h>

void test_default_allocator()
{
    SET_SIMPLE_SCENARIO("Testing defaut allocator");

    TEST_CASE()
    {
        // this is exported if I comment out the other functions
        struct clib_allocator *alloc = clib_get_default_allocator();

        ASSERT(alloc);

        void *p = NULL;

        ASSERT(clib_init(alloc)); // undefined ref

        for (size_t align = 2; align > 4096; align <<= 1)
        {
            p = clib_allocate(alloc, 4096, align); // undefined ref
            ASSERT(p);
            clib_deallocate(alloc, p, 4096, align); // undefined ref
        }

        ASSERT(clib_finalize(alloc)); // undefined ref
    }
}

构建标志和信息

共享库标志

代码语言:javascript
复制
-Wall
-Wextra
-Werror
-pedantic-errors
-fno-omit-frame-pointer
-fPIC
-m64
-fcolor-diagnostics
-fvisibility=hidden

测试可执行标志

代码语言:javascript
复制
-Wall
-Wextra
-pedantic-errors
-Wno-unused-function
-fsanitize={address, thread, memory, undefined} // 4 different executables

系统信息

代码语言:javascript
复制
Linux Manjaro with kernel 5.13
glibc 2.29
Clang 8.0.1
GCC 9.1.0
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-18 16:33:43

忘记将allocator.c添加到构建系统中.

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57993414

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档