You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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中的断言失败。

具体解决步骤:

  1. 清理残留编译产物
    删除所有旧的目标文件和静态库,避免跨平台格式文件干扰:
    rm -rf c_datastructures/bin/*.a c_datastructures/*.o
    
  2. 重新编译并指定平台兼容选项
    使用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参数生成位置无关代码,既保证库的跨环境可用性,也能规避链接器的重定位异常。
  3. 升级Binutils版本
    若清理后仍报错,可升级Binutils到2.39及以上版本(该版本修复了该断言bug):
    sudo apt update && sudo apt install --only-upgrade binutils
    
  4. 检查跨平台类型定义一致性
    确保自定义类型(如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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 02:17:02