GCC编译出现dangerous relocation警告及链接段错误求助
解决WSL Ubuntu下GCC编译BFD断言失败问题
问题背景
我开发的C语言库中有一个copy_object函数,负责动态分配内存并复制对象,代码如下:
/// @brief dynamically allocates a copy of an object /// @param obj_ptr a pointer to the object /// @param obj_size the size of the object /// @return a pointer to the copy extern void *copy_object(void *obj_ptr , size_t obj_size){ void *copy = calloc(1 , obj_size); if(!copy){ return NULL; } memcpy(copy , obj_ptr , obj_size); return copy; }
该函数在Windows平台编译完全正常,但在WSL Ubuntu 22.04.3环境下使用GCC 11.4.0编译时,出现链接器断言失败错误:
/usr/bin/ld: BFD (GNU Binutils for Ubuntu) 2.38 assertion fail ../../bfd/reloc.c:8580 c_datastructures/bin//liblinked_list.a(copy_object.o):copy_object.c:(.pdata+0x0): dangerous relocation: collect2: fatal error: ld terminated with signal 11 [Segmentation fault] compilation terminated.
链表模块相关代码参考:
#include "../headers/copy_object.h" #include <stdlib.h> #include "../headers/linked_list.h" struct node { struct node *prev; void *obj_ptr; size_t obj_size; free_func *free_obj; struct node *next; }; struct linked_list { u64 node_no; node *first_node; node *last_node; }; linked_list *new_linked_list(){ return (linked_list *) calloc(1 , sizeof(linked_list)); } void linked_list_free_node(node *node_ptr){ if(!node_ptr){ return; } free(node_ptr -> obj_ptr); free(node_ptr); } void free_linked_list_contents(linked_list *list_ptr){ if(!list_ptr){ return; } for(node *curr_node = list_ptr -> first_node , *tmp ; curr_node ; curr_node = tmp){ tmp = curr_node -> next; linked_list_free_node(curr_node); } list_ptr -> first_node = NULL; list_ptr -> last_node = NULL; list_ptr -> node_no = 0; } datastruct_err destroy_linked_list(linked_list *list_ptr){ if(!list_ptr){ return Invalid_Input; } if(list_ptr -> first_node){ free_linked_list_contents(list_ptr); } free(list_ptr); return Success; } node *linked_list_create_node(void *obj_ptr , size_t obj_size , free_func *free_obj){ if(!obj_ptr || !obj_size){ return NULL; } node *ret = (node *) calloc(1 , sizeof(node)); if(!ret){ return NULL; } ret -> obj_ptr = copy_object(obj_ptr , obj_size); if(!ret -> obj_ptr){ free(ret); return NULL; } ret -> obj_size = obj_size; if(free_obj){ ret -> free_obj = free_obj; }else{ ret -> free_obj = free; } return ret; } datastruct_err linked_list_add_node(void *obj_ptr , size_t obj_size , free_func *free_obj , linked_list *list_ptr){ if(!obj_ptr || !list_ptr || !obj_size){ return Invalid_Input; } node *new_node = linked_list_create_node(obj_ptr , obj_size , free_obj); if(!new_node){ return Allocation_err; } if(!list_ptr -> first_node){ list_ptr -> first_node = list_ptr -> last_node = new_node; }else{ node *target = list_ptr -> last_node; list_ptr -> last_node = new_node; new_node -> prev = target; target -> next = new_node; } list_ptr -> node_no++; return Success; } node *linked_list_get_node(u64 index , linked_list *list_ptr){ if(!list_ptr){ return NULL; } if(index >= list_ptr -> node_no){ return NULL; } u64 i = 0; node *ret = NULL; if(index <= list_ptr -> node_no / 2){ for(ret = list_ptr -> first_node ; ret != NULL && i < index ; ret = ret -> next , i++){} }else{ for(ret = list_ptr -> last_node , i = list_ptr -> node_no - 1; ret && i > index ; ret = ret -> prev , i--){} } return ret; } datastruct_err linked_list_delete_node(u64 index , linked_list *list_ptr){ if(!list_ptr){ return Invalid_Input; } if(index >= list_ptr -> node_no){ return Invalid_Input; } node *target = linked_list_get_node(index , list_ptr); if(index == 0){ list_ptr -> first_node = list_ptr -> first_node -> next; if(list_ptr -> node_no == 1){ list_ptr -> last_node = NULL; }else{ target -> next -> prev = target -> prev; } }else{ if(index == list_ptr -> node_no - 1){ list_ptr -> last_node = list_ptr -> last_node -> prev; }else{ target -> next -> prev = target -> prev; } target -> prev -> next = target -> next; } linked_list_free_node(target); list_ptr -> node_no--; return Success; } node *linked_list_get_first_node(linked_list *list_ptr){ if(!list_ptr){ return NULL; } return list_ptr -> first_node; } node *linked_list_get_last_node(linked_list *list_ptr){ if(!list_ptr){ return NULL; } return list_ptr -> last_node; } u64 linked_list_get_node_no(linked_list *list_ptr){ if(!list_ptr){ return 0; } return list_ptr -> node_no; } node *linked_list_get_prev_node(node *node_ptr){ if(!node_ptr){ return NULL; } return node_ptr -> prev; } node *linked_list_get_next_node(node *node_ptr){ if(!node_ptr){ return NULL; } return node_ptr -> next; } void *linked_list_get_obj_ptr(node *node_ptr){ if(!node_ptr){ return NULL; } return node_ptr -> obj_ptr; } size_t linked_list_get_obj_size(node *node_ptr){ if(!node_ptr){ return 0; } return node_ptr -> obj_size; }
问题分析与解决
这个错误并非代码逻辑问题,是GNU Binutils 2.38的已知bug,出现在链接器处理混合格式目标文件(比如残留的Windows PE/COFF格式文件和Linux ELF格式文件)时,触发了reloc.c中的断言失败。
具体解决步骤:
- 清理残留编译产物
删除所有旧的目标文件和静态库,避免跨平台格式文件干扰:rm -rf c_datastructures/bin/*.a c_datastructures/*.o - 重新编译并指定平台兼容选项
使用Linux标准编译参数重新编译,生成ELF格式目标文件:gcc -c copy_object.c linked_list.c -Wall -Wextra -fPIC ar rcs liblinked_list.a copy_object.o linked_list.o-fPIC参数生成位置无关代码,既保证库的跨环境可用性,也能规避链接器的重定位异常。 - 升级Binutils版本
若清理后仍报错,可升级Binutils到2.39及以上版本(该版本修复了该断言bug):sudo apt update && sudo apt install --only-upgrade binutils - 检查跨平台类型定义一致性
确保自定义类型(如u64、datastruct_err、free_func)在Windows和Linux下定义一致,比如u64应统一为:
避免因类型大小差异导致的编译/链接隐式错误。typedef unsigned long long u64;
验证方式
编译完成后,用file命令检查目标文件格式,确认是Linux下的ELF格式:
file copy_object.o
正常输出应包含:ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV)
内容的提问来源于stack exchange,提问作者abdelrahman Mohamed
相关产品推荐
相关产品推荐

