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

Clang15编译代码出现段错误的原因分析与修复方案问询

x86平台Clang 15/17编译含ifunc的代码触发段错误

以下代码在x86平台使用Clang 15/17编译运行时会出现段错误:

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <sys/auxv.h>
// Provide default macro definitions in case that they are not defined on current linux distro.
// For example, TiFlash compiled on older linux kernels may also be used in newer ones.
// These values should be stable for Linux: only false negative is expected when running on
// older kernels, but it is acceptable as `google/cpu_features` is also doing so.
#ifndef HWCAP2_MTE
#define HWCAP2_MTE (1 << 18)
#endif
#ifndef HWCAP_SVE
#define HWCAP_SVE (1 << 22)
#endif
#ifndef AT_HWCAP2
#define AT_HWCAP2 26
#endif
#ifndef AT_HWCAP
#define AT_HWCAP 16
#endif
/// check if MTE is supported in current environment
static inline bool mte_supported(void)
{
    return (getauxval(AT_HWCAP2) & HWCAP2_MTE) != 0;
}
/// check if SVE is supported in current environment
static inline bool sve_supported(void)
{
    return (getauxval(AT_HWCAP) & HWCAP_SVE) != 0;
}
#define STRINGIFY_IMPL(X) #X
#define STRINGIFY(X) STRINGIFY_IMPL(X)
/**
 *  \brief
 *  Symbol is defined as hidden visibility. Therefore, implementations here are only to override routines with TiFlash
 *  binary itself. This is because dependencies like `ld.so`, `libgcc_s.so`, etc will need essential routines like
 *  `memcpy` to finish the early loading procedure. Therefore, declare such symbols as visible indirect function will
 *  create cyclic dependency. It shall be good enough to override symbols within TiFlash, as most heavy computation works
 *  are happening in the main binary.
 *  \param NAME: exported symbol name
 *  \param SVE: preferred implementation when SVE is available
 *  \param MTE: preferred implementation when MTE is available
 *  \param ASIMD: preferred implementation for generic aarch64 targets (ASIMD is required by default for Armv8 and above)
 */
#define DISPATCH(NAME, SVE, MTE, ASIMD)                                                                                  \
    extern typeof(ASIMD) __tiflash_##NAME __attribute__((ifunc(STRINGIFY(__tiflash_##NAME##_resolver))));                \
    extern typeof(ASIMD) NAME __attribute__((visibility("hidden"), alias(STRINGIFY(__tiflash_##NAME))));                 \
    _Pragma("GCC diagnostic push")                                                                                       \
        _Pragma("GCC diagnostic ignored \"-Wunused-function\"") static typeof(ASIMD) * __tiflash_##NAME##_resolver(void) \
    {                                                                                                                    \
        if (sve_supported())                                                                                             \
        {                                                                                                                \
            return SVE;                                                                                                  \
        }                                                                                                                \
        if (mte_supported())                                                                                             \
        {                                                                                                                \
            return MTE;                                                                                                  \
        }                                                                                                                \
        return ASIMD;                                                                                                    \
    }                                                                                                                    \
    _Pragma("GCC diagnostic pop")
#undef memcpy
DISPATCH(memcpy, memcpy, memcpy, memcpy)
int main() {
    char source[] = "once upon a daydream...", dest[4];
        memcpy(dest, source, sizeof dest);
    return 0;
}

已做的测试与观察

  • Clang 13及GCC编译运行无段错误;
  • Clang 15/17编译运行触发段错误;
  • 设置LD_BIND_NOW=1运行时无段错误;
  • 移除extern typeof(ASIMD)相关代码后可正常运行,确认问题与ifunc机制相关。

调试细节:Clang15/17中getauxval通过PLT解析(调用getauxval@plt),而GCC或Clang13中直接调用。查看getauxval@plt的汇编后,预期其GOT表项应为PLT后续指令地址或getauxval真实地址,但实际调试显示为0x1936,完全不符合预期。

待解答问题

  1. 0x1936的来源是什么?推测与ifunc或动态库加载顺序有关,但难以定位根源;
  2. 如何修复代码?因LD_BIND_NOW=1在ARM平台无效。

补充内容1:测试GCC文档示例未达预期

按GCC文档编写如下测试代码,未输出预期的"aaaaa":

#include <stdio.h>

void *my_memcpy (void *dst, const void *src, size_t len)
{
    printf("aaaaa\n");
    return dst;
}

static void * (*resolve_memcpy (void))(void *, const void *, size_t)
{
    return my_memcpy;
}

void *memcpy (void *, const void *, size_t) __attribute__ ((ifunc ("resolve_memcpy")));

extern void *memcpy (void *, const void *, size_t);

int main() {
    char source[] = "once upon a daydream...", dest[4];
    memcpy(dest, source, sizeof dest);
    return 0;
}

补充内容2:能否移除#define memcpy memcpy2?

现有代码通过宏替换将memcpy指向自定义的ifunc符号memcpy2,询问是否可以移除该宏:

#include <stdio.h>
#include <string.h>

static int use_embed = 1;

void *my_memcpy (void *dst, const void *src, size_t len)
{
    printf("aaaaa\n");
    return dst;
}

static void * (*resolve_memcpy (void))(void *, const void *, size_t)
{
    if(use_embed == 1) {
        return memcpy;
    } else {
        return my_memcpy;
    }
}

void *memcpy2 (void *, const void *, size_t) __attribute__ ((ifunc ("resolve_memcpy")));

#define memcpy memcpy2

// extern void *memcpy (void *, const void *, size_t);

int main() {
    int source = 5;
    int dest = 6;
    memcpy(&dest, &source, sizeof(source));
    printf("%d %d\n", use_embed, dest);
    return 0;
}

核心需求

  1. 能否从C库导入memcpy并命名为memcpy_origin,同时重定义非宏类型的memcpy,使其可调用memcpy_origin或自定义my_memcpy?
  2. 能否在动态库加载阶段,决定是使用C库的memcpy还是自定义实现?

内容的提问来源于stack exchange,提问作者calvin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:22:05