当前位置: 首页 > news >正文

网站服务器租用价格多少钱一年网络营销优化培训

网站服务器租用价格多少钱一年,网络营销优化培训,WordPress标题别名自动翻译插件,wordpress双语切换按钮一、绪论 作为 C/C 的开发者#xff0c;大多数都会清楚课本上动态库以及静态库的优缺点#xff0c;在教科书上谈及到动态库的一个优点是可以节约磁盘和内存的空间#xff0c;多个可执行程序通过动态库加载的方式共用一段代码段 #xff1b;而时至今日#xff0c;再看看上…一、绪论 作为 C/C 的开发者大多数都会清楚课本上动态库以及静态库的优缺点在教科书上谈及到动态库的一个优点是可以节约磁盘和内存的空间多个可执行程序通过动态库加载的方式共用一段代码段 而时至今日再看看上面这一句更多则是调侃说的都对就是很难实施可能连 GNU 当初都没有意识到后来动态库一个的用途竟然是处理同名符号冲突的问题只有动态库才能处理同名符号问题静态库是不行的。 本文着重讲解的内容可以分为: 同名符号冲突的两种形式同名符号的解决策略 在这个过程中也会讲述到排查同名符号冲突的有效手段以及与解决与同名符号相关 GNU 链接选项的作用。 为了更为直观而且具有可复现操作性本文还专门构建了一个用于演示的 Demo本文的所有结论均以理论和实践的形式给出为此也会花一点时间去讲解整一个 Demo 示例的组成Demo项目为一个未提交的 git 仓库每一条 commit 均有其对应的价值项目可直接编译。 二、同名符号的两种形式 在讲解同名符号之前我觉得首先得对符号有一个清楚的认知即符号是什么谁会使用到符号? 符号(symbol)一词来自于GNU的ELFExecutable and Linking Format而 ELF 文件大致上可以分为动静态库和可执行程序两类通过链接动静态库完成可执行程序的构建所以符号是针对于链接而言的符号冲突跟编译一毛钱关系都没有符号冲突只跟链接有关系。 1. 示例项目1 下面这个部分如果不敢兴趣可以跳过这里讲解的是如果在一个 cmake 工程中实现这种比较 “鬼畜” 的操作: 整一个的项目目录如下图所示: ├── cmake │ ├── strong_symbol.cmake │ └── weak_symbol.cmake ├── CMakeLists.txt ├── lib │ ├── lib_strong_shared_symbol.so │ ├── lib_strong_static_symbol.a │ ├── libstrong_symbol.a │ ├── libstrong_symbol.so │ ├── lib_weak_shared_symbol.so │ ├── lib_weak_static_symbol.a │ ├── libweak_symbol.a │ └── libweak_symbol.so ├── main.cpp └── src├── strong_symbol.cpp├── symbol.h└── weak_symbol.cpp其中 strong_symbol.cmake 生成了 libstrong_symbol.aweak_symbol.cmake 则生成了 libweak_symbol,a, 而 CmakeLists.txt 则在生成 symbol 可执行程序时同时链接到了 libstrong_symbol.a 和 libweak_symbol.a 要想在一个 cmake 工程时实现这种 “鬼畜” 的做法需要注意的就是控制每一个环节的 *.o 文件不妨通过下面三个文件的实现自己感受一下: 1strong_symbol.cmake set(SRCS ${CMAKE_SOURCE_DIR}/src/symbol.h${CMAKE_SOURCE_DIR}/src/strong_symbol.cpp)SET(CMAKE_C_FLAGS -fPIC) SET(CMAKE_CXX_FLAGS -fPIC)ADD_LIBRARY(${STRONG_SYMBOL_LIB} SHARED ${SRCS})2weak_symbol.cmake set(SRCS ${CMAKE_SOURCE_DIR}/src/symbol.h${CMAKE_SOURCE_DIR}/src/weak_symbol.cpp)SET(CMAKE_C_FLAGS -fPIC ) SET(CMAKE_CXX_FLAGS -fPIC )ADD_LIBRARY(${WEAK_SYMBOL_LIB} SHARED ${SRCS})3CMakeLists.txt cmake_minimum_required (VERSION 3.5)project(symbol)set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 14)set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)# 动态库名称 set(WEAK_SYMBOL_LIB weak_symbol) set(STRONG_SYMBOL_LIB strong_symbol)include(${CMAKE_SOURCE_DIR}/cmake/weak_symbol.cmake) include(${CMAKE_SOURCE_DIR}/cmake/strong_symbol.cmake)link_directories(${CMAKE_SOURCE_DIR}/lib)set(SRCS ${CMAKE_SOURCE_DIR}/src/symbol.h${CMAKE_SOURCE_DIR}/main.cpp) add_executable(${PROJECT_NAME} ${SRCS}) target_link_libraries(${PROJECT_NAME} ${WEAK_SYMBOL_LIB} ${STRONG_SYMBOL_LIB})4symbol符号(函数)的两种实现 // strong_symbol.cpp #include symbol.h#include iostreamvoid symbol() {std::cout strong symbol std::endl; }// weak_symbol.cpp #include symbol.h#include iostreamvoid symbol() {std::cout weak symbol std::endl; }还是挺有意思的一种实现可以了解一下这种技术在完成C单元测试Mock测试时也会被广泛使用到。 2. 符号冲突类型 GNU 的符号冲突可以分类两类一类是显式符号冲突另一类则是隐式符号冲突。 1显式符号冲突 显式符号冲突会在编译阶段直接报错而隐式符号冲突则在编译阶段不会有任何问题隐式符号冲突会导致程序运行时跳转至错误的符号进而执行错误的代码段造成不可预知的后果。 以上文演示的 示例项目1 为例在编译时通过 gcc 传递 -Wl,-–verbose 给 ld可以看到链接的详细过程可以看到以下内容: 试图打开 CMakeFiles/symbol.dir/main.cpp.o 成功 CMakeFiles/symbol.dir/main.cpp.o 试图打开 ../lib/libweak_symbol.a 成功 (../lib/libweak_symbol.a)weak_symbol.cpp.o 试图打开 ../lib/libstrong_symbol.a 成功 // 这里是空着的请注意 试图打开 /home/haorui/haorui/symbol/lib/libstdc.so 失败 试图打开 /home/haorui/haorui/symbol/lib/libstdc.a 失败仔细观察可以看到链接器在打开 libweak_symbol.a 从其中读取了 weak_symbol.cpp.o而 libstrong_symbol.a 仅仅只是被打开了并没有读取任何 .o 文件这是因为在链接过程中存在符号抢占的问题即链接器对于默认的符号加载会优先保留第一个加载的符号忽略后续的同名符号并且持续服用第一个加载的同名符号所以最后可执行程序的输出结果为 weak symbol . GNU 的 ld 还提供了一个指令能够让我们实现强制归档该指令能够强制导入静态库的符号无论需要与否可以简单的将 CMakeLists.txt 进行下面的修改: // from target_link_libraries(${PROJECT_NAME} ${WEAK_SYMBOL_LIB} ${STRONG_SYMBOL_LIB} ) // to target_link_libraries(${PROJECT_NAME} -Wl,--whole-archive ${WEAK_SYMBOL_LIB} ${STRONG_SYMBOL_LIB} -Wl,--no-whole-archive)再一次观看 ld 的链接过程可以发现链接报错出现显式符号冲突的现象两个静态库所包含的 .o 文件都被包含进来了: 试图打开 CMakeFiles/symbol.dir/main.cpp.o 成功 CMakeFiles/symbol.dir/main.cpp.o 试图打开 ../lib/libweak_symbol.a 成功 (../lib/libweak_symbol.a)weak_symbol.cpp.o 试图打开 ../lib/libstrong_symbol.a 成功 // 注意这个 (../lib/libstrong_symbol.a)strong_symbol.cpp.o 试图打开 /home/haorui/haorui/symbol/lib/libstdc.so 失败 // ... // 显式符号冲突 /usr/bin/ld: ../lib/libstrong_symbol.a(strong_symbol.cpp.o): in function symbol(): strong_symbol.cpp:(.text0x0): multiple definition of symbol(); ../lib/libweak_symbol.a(weak_symbol.cpp.o):weak_symbol.cpp:(.text0x0): first defined here三、同名符号的解决策略 同名符号的解决思路有且只有两种方式它们的原理是不相同的: 利用 ELF 中的符号的强弱特性利用动态库运行时加载的特性提供重复加载的机制 值得一提的是无论是何种解决方式最终的解决方式一定都是以动态库的形式给出静态库不能解决符号冲突的原因稍后也会揭示; 1. 示例项目 2 为了能够演示这种复杂的案例需要将 示例项目1 进行一些改动,演化为 示例项目2它的项目视图如下: 项目的解释以及构建可以参考示例项目1这里就不在赘述。 2. 利用 ELF 中的符号的强弱特性 在解释如何利用 ELF 符号的强弱特性来解决同名符号冲突之前首先还是得回到强弱符号是针对于谁而言的以及强弱的定义。 ELF 的强弱符号与GCC 动态库符号导出技术息息相关在本文最前面曾经提到过符号是针对于ld 链接而言的故强弱符号肯定也是在这上面做文章我们知道动态库有一个特性就是运行时加载换句话说就是可执行程序中并不包含动态库内的代码段链接器要的只是动态库的入口符号即直接可执行程序直接调用的接口我们知道函数的一个特性就是封装、嵌套调用动态库对可执行程序直接暴露的接口即为入口符号而这些实现这些入口符号所调用符号则对链接器而言是无用因为可执行程序中既不需要调用这些符号也不需要这些符号的实现,这些符号是可以设置为弱符号的。 故我们可以简单的将强符号理解为对链接器可见的符号弱符号则理解为对链接器不可见的符号另一个方式理解则是动态库符号导出的符号即为强符号反之则为弱符号。 如何查看动/静态库的某一符号的强弱 在 GNU 平台上动态库和静态库都是 ELF 格式的符号的相关描述查看 ELF 即可知道linux 下面查看的工具大致上有两个 readelf 和 objdump下文以 objdump 作为演示,演示的案例使用 示例项目 2 : _symbol 符号为 global # objdump -x libstrong_symbol1.so # 段内偏移 | 符号作用域 | 符号类型 | 符号所在段 | 符号对应的对象占据的内存空间大小 | 符号名 # 符号作用域 : g - global , l - local # Hint : _Z13strong_symbolv 、_Z7_symbolv 0000000000001145 g F .text 000000000000000c _Z13strong_symbolv 0000000000000000 F *UND* 0000000000000000 __cxa_atexitGLIBC_2.2.5 00000000000011af g F .text 0000000000000032 _Z7_symbolv 0000000000000000 F *UND* 0000000000000000 _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKcGLIBCXX_3.4 0000000000000000 F *UND* 0000000000000000 _ZNSolsEPFRSoS_EGLIBCXX_3.4 0000000000000000 O *UND* 0000000000000000 _ZSt4coutGLIBCXX_3.4 0000000000000000 F *UND* 0000000000000000 _ZNSt8ios_base4InitC1EvGLIBCXX_3.4 0000000000000000 w *UND* 0000000000000000 _ITM_deregisterTMCloneTable 0000000000000000 w *UND* 0000000000000000 __gmon_start__ 0000000000000000 w *UND* 0000000000000000 _ITM_registerTMCloneTable 0000000000000000 F *UND* 0000000000000000 _ZNSt8ios_base4InitD1EvGLIBCXX_3.4_symbol 符号为 local # objdump -x libstrong_symbol2.so # 段内偏移 | 符号作用域 | 符号类型 | 符号所在段 | 符号对应的对象占据的内存空间大小 | 符号名 # 符号作用域 : g - global , l - local # Hint : _Z13strong_symbolv 、_Z7_symbolv 00000000000011af l F .text 000000000000004d _Z7_symbolv 0000000000001000 l F .init 0000000000000000 _init 0000000000003da8 l O .dynamic 0000000000000000 _DYNAMIC 0000000000004048 l O .data 0000000000000000 __TMC_END__ 0000000000004000 l O .got.plt 0000000000000000 _GLOBAL_OFFSET_TABLE_ 0000000000000000 F *UND* 0000000000000000 printfGLIBC_2.2.5 0000000000000000 w F *UND* 0000000000000000 __cxa_finalizeGLIBC_2.2.5 0000000000000000 F *UND* 0000000000000000 _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_GLIBCXX_3.4 0000000000001145 g F .text 000000000000000c _Z13strong_symbolv 0000000000000000 F *UND* 0000000000000000 __cxa_atexitGLIBC_2.2.5 0000000000000000 F *UND* 0000000000000000 _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKcGLIBCXX_3.4 0000000000000000 F *UND* 0000000000000000 _ZNSolsEPFRSoS_EGLIBCXX_3.4 0000000000000000 O *UND* 0000000000000000 _ZSt4coutGLIBCXX_3.4 0000000000000000 F *UND* 0000000000000000 _ZNSt8ios_base4InitC1EvGLIBCXX_3.4 0000000000000000 w *UND* 0000000000000000 _ITM_deregisterTMCloneTable 0000000000000000 w *UND* 0000000000000000 __gmon_start__ 0000000000000000 w *UND* 0000000000000000 _ITM_registerTMCloneTable 0000000000000000 F *UND* 0000000000000000 _ZNSt8ios_base4InitD1EvGLIBCXX_3.4总结 先说明一下背景在 libstrong_symbolx.so 中的 _symbol 即为同名函数 与 libweak_symbol.so 中的 _symbol 冲突strong_symbol 和 weak_symbol 同时都调用了 _symbol 符号 但是它们各自 _symbol 的实现是不同的。 主程序代码如下: int main() {strong_symbol();weak_symbol();return 0; }在 libstrong_symbol1.so 的情况下输出: strong symbol address is 0x7f5b582a01af strong symbol strong symbol address is 0x7f5b582a01af strong symbol在 libstrong_symbol2.so 的情况下输出: strong symbol address is 0x7fc4904a01af strong symbol weak symbol address is 0x7fc49049b1af weak symbol2符号隐藏的两种方式 -fvisibilityhidden 这个选项是传递给编译器的添加这个选项之后动态库导出符号的默认行为都为本地符号即弱符号在程序中针对需要导出的符号需要显式添加 __attribute__((visibility(default)))关键字。 这里有一点需要注意的地方是 -fvisibilityhidden 的适用范围是 *.o 文件即 *.cpp , 动态库链接静态库时也会将静态库中的符号导入动态库这些符号的可见性是不受 -fvisibilityhidden 的影响的。 -Wl,–exclude-libsALL 这个选项是传递给链接器的并且具有明确的使用场景生成动态库时导入静态库符号时将静态库的符号的可见性全部设置为不可见这句话有点绕但是需要好好理解。 以上图为例lib_weak_symbol.a 存在 symbol 符号可见性为显性; 在生成 lib_weak_symbol.so 时需要将 lib_weak_symbol.a 的代码段拉进 libweak_symbol.so , 在这个时候 lib_weak_symbol.a 中的 _symbol 符号也会被导入默认是强符号添加 -Wl,–exclude-libsALL 即可把 _symbol 符号的可见性设置为不可见即弱符号从这个案例中可以看出-Wl,–exclude-libsALL 的使用场景是使用 静态库去生成动态库的过程中生效的例如使用静态库生成静态库那么这种情况下就不适用了。 静态库为何处理不了同名符号 其实回答这个问题很简单对于静态库而言没有所谓的强弱符号的说法因为静态库的所谓代码段都会被导入到可执行程序真要说的话那么静态库的符号只有强符号一种也可以从另外一种角度去理解 静态库的本质就是 *.o 文件的归档再退一步就是 *.cpp 因为静态库的全部符号直接使用到的或者间接使用到的均会导入到可执行程序同一个代码段是不允许出现同名符号的。 动态库通过一些针对性的操作之所以能够实现同名函数的兼容实际上是通过符号隐藏让两个同名函数放置在不同的动态库内本质上是没有违背同一代码段不能出现同名符号的规则的。 3. 利用动态库运行时加载的特性提供重复加载的机制 这个机制非常暴力利用的是链接器的一个可选配置 -Wl,-Bsymbolic。 正常情况下在linux平台上(不使用-Bsymbolic)加载的目标文件中第一次出现的符号将在程序中一直被使用不论是定义在静态可执行部分还是在动态目标文件中。 这是通过**符号抢占(symbol preemption)**来实现的。动态加载器构建符号表所有的动态符号根据该符号表被决议。所以正常情况下如果一个符号实例出现在动态库DSO中但是已经在静态可执行文件或者之前加载的动态库中被定义那么以前的定义也将被用于当前的动态库中。 -Bsymbolic 通过关闭DOS中的符号抢占来改变这种行为也就是关闭了上述这种机制使用 Bsymbolic 之后无论是已经加载过还是没有加载过目标符号都会被重复 加载也就是 -Bsymbolic 是通过将共享行为变更为拷贝行为来实现同名符号兼容。 正如本文最初的调侃动态库的一个优点是可以节约磁盘和内存的空间多个可执行程序通过动态库加载的方式共用一段代码段在当下为了同一个库的不同版本问题已经慢慢失去了其共享的价值了。
http://www.w-s-a.com/news/271464/

相关文章:

  • 有什么做任务拿钱的网站精准的搜索引擎优化
  • 洛阳有建社网站的吗电力建设工程质量监督总网站
  • 网站404报错热水器网站建设 中企动力
  • 网站降权恢复淘宝 网站建设
  • 安州区建设局网站台州优秀关键词优化
  • 网站假设教程湖南微信管理系统
  • 网站备案属于公司哪一块哪个网站是专门做封面素材
  • 广州个人做网站内江建设局网站
  • 网站开发 360百科大连哪里有手机自适应网站建设维护
  • 如何查网站pv网站功防教程
  • 建设银行网站信息补充营销推广的作用
  • 网站见建设seo外链自动群发工具
  • 在境外做网站网站团购网站seo
  • 进网站后台加什么360推广 网站建设
  • 网站备案号码专做网站漏扫的工具
  • 罗店网站建设wordpress响应式
  • 网站怎么制作小程序wordpress实时获取qq资料
  • 网站的流量怎么赚钱经销做网站都有什么好处
  • 如何做好网站首页企术建站
  • 杭州网站建设咨询蓝韵网络聊城有制作网站的吗
  • 网站开发注意的事项深圳企业网站
  • 哈尔滨网站制作哪里专业网站建设维护有哪些内容
  • 花的网站建设规划书网络营销培训
  • 又拍云wordpress全站cdn无锡做网站品牌公司
  • 计算机网络工程网站建设黄石建设信息网站
  • 旅游网站开发毕业设计开题报告青岛网站建设服务公司
  • 人员调动在网站上怎么做网站开发课程意见和建议
  • 卓训网是个什么网站wordpress命令执行时间
  • 网站建设需要做哪些工作网片焊接
  • 网站优化方案dedecms win8风格网站模板