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

使用LLVM插件改写MSAsmStmt时触发段错误问题排查

问题:LLVM插件处理MSAsmStmt时调用Rewriter.ReplaceText触发段错误

我编写了包含__asm内联汇编块的C代码,希望开发LLVM插件自动为汇编块插入.loc调试指令以支持单步调试。插件可检测到MSAsmStmt语句,但调用Rewriter.ReplaceText接口时触发段错误,问题定位到Rewriter.getRangeSize函数。已验证源范围有效且非宏展开,可正常读取AST,仅调用Rewriter时出错。使用M2 MacBook Pro,测试过clang 16.0.6和19.1.1版本。请问实现思路是否正确?为何会触发段错误?


原C代码

#include <inttypes.h>
#include <stdio.h>

uint8_t count1(uint32_t x) {
    int out;
    __asm {
        mov edx, [x]
        mov al, 0
next:   cmp edx, 0
        je done
        mov cl, dl
        and cl, 1
        add al, cl
        shr edx, 1
        jmp next
done:
        mov out, al
    }
    return out;
}

int main() {
    uint32_t x = 0x5789ABCD;
    uint8_t cnt = count1(x);
    printf("Number of 1s in 0x%X: %hhu\n", x, cnt);
}

目标转换后代码

#include <inttypes.h>
#include <stdio.h>

uint8_t count1(uint32_t x) {
    int out;
    __asm {
        .file 1 "main.c"
        .loc 1 7
        mov edx, [x]
        .loc 1 8
        mov al, 0
        .loc 1 9
next:   cmp edx, 0
        .loc 1 10
        je done
        .loc 1 11
        mov cl, dl
        .loc 1 12
        and cl, 1
        .loc 1 13
        add al, cl
        .loc 1 14
        shr edx, 1
        .loc 1 15
        jmp next
done:
        .loc 1 17
        mov out, al
    }
    return out;
}

int main() {
    uint32_t x = 0x5789ABCD;
    uint8_t cnt = count1(x);
    printf("Number of 1s in 0x%X: %hhu\n", x, cnt);
}

插件核心代码

class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> {
  public:
    explicit MyASTVisitor(ASTContext *Context, Rewriter &R)
        : Context(Context), TheRewriter(R) {}

    bool VisitStmt(Stmt *S) {
        if (auto *Asm = dyn_cast<MSAsmStmt>(S)) {
            StringRef AsmString = Asm->getAsmString();
            SourceLocation StartLoc = Asm->getBeginLoc();
            SourceLocation EndLoc = Asm->getEndLoc();
            bool result = TheRewriter.ReplaceText(SourceRange(StartLoc, EndLoc), AsmString);
            llvm::errs() << "Replace result: " << result << "\n";
        }
        return true;
    }

  private:
    ASTContext *Context;
    Rewriter &TheRewriter;
};

错误栈信息

0.      Program arguments: /opt/homebrew/Cellar/llvm@16/16.0.6_1/bin/clang-16 -cc1 -triple x86_64-apple-macosx15.0.0 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name testfile.c -mrelocation-model pic -pic-level 2 -mframe-pointer=all -ffp-contract=on -fno-rounding-math -funwind-tables=2 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -target-cpu penryn -tune-cpu generic -mllvm -treat-scalable-fixed-error-as-warning -debug-info-kind=standalone -dwarf-version=4 -debugger-tuning=lldb -target-linker-version 1053.12 -fcoverage-compilation-dir=/Users/jurajpetras/dev/asm_debug -resource-dir /opt/homebrew/Cellar/llvm@16/16.0.6_1/lib/clang/16 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk/usr/local/include -internal-isystem /opt/homebrew/Cellar/llvm@16/16.0.6_1/lib/clang/16/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk/usr/include -O0 -fdebug-compilation-dir=/Users/jurajpetras/dev/asm_debug -ferror-limit 19 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fmax-type-align=16 -fcolor-diagnostics -fasm-blocks -load ./build/libasm_debug.dylib -add-plugin asm_debug -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/folders/88/yqhhhgms02vcwxdp_x2dgbp40000gn/T/testfile-0c3ab4.o -x c testfile.c
1.      <eof> parser at end of file
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  libLLVM.dylib            0x0000000110344b20 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  libLLVM.dylib            0x00000001103439a4 llvm::sys::RunSignalHandlers() + 112
2  libLLVM.dylib            0x00000001103451b4 SignalHandler(int) + 360
3  libsystem_platform.dylib 0x0000000199b08184 _sigtramp + 56
4  libasm_debug.dylib       0x00000001091de914 clang::Rewriter::getRangeSize(clang::CharSourceRange const&, clang::Rewriter::RewriteOptions) const + 212
5  libasm_debug.dylib       0x00000001091deb74 clang::Rewriter::getRangeSize(clang::SourceRange, clang::Rewriter::RewriteOptions) const + 36
6  libasm_debug.dylib       0x0000000108acc49c clang::Rewriter::ReplaceText(clang::SourceRange, llvm::StringRef) + 100
7  libasm_debug.dylib       0x0000000108acc30c (anonymous namespace)::MyASTVisitor::VisitStmt(clang::Stmt*) + 180
8  libasm_debug.dylib       0x0000000108acc22c clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::WalkUpFromStmt(clang::Stmt*) + 36
9  libasm_debug.dylib       0x0000000108acc170 clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::WalkUpFromAsmStmt(clang::AsmStmt*) + 48
10 libasm_debug.dylib       0x0000000108aa3b3c clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::WalkUpFromMSAsmStmt(clang::MSAsmStmt*) + 48
11 libasm_debug.dylib       0x0000000108aa3978 clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::TraverseMSAsmStmt(clang::MSAsmStmt*, llvm::SmallVectorImpl<llvm::PointerIntPair<clang::Stmt*, 1u, bool, llvm::PointerLikeTypeTraits<clang::Stmt*>, llvm::PointerIntPairInfo<clang::Stmt*, 1u, llvm::PointerLikeTypeTraits<clang::Stmt*>>>>*) + 80
12 libasm_debug.dylib       0x0000000108aa1184 clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::dataTraverseNode(clang::Stmt*, llvm::SmallVectorImpl<llvm::PointerIntPair<clang::Stmt*, 1u, bool, llvm::PointerLikeTypeTraits<clang::Stmt*>, llvm::PointerIntPairInfo<clang::Stmt*, 1u, llvm::PointerLikeTypeTraits<clang::Stmt*>>>>*) + 144
13 libasm_debug.dylib       0x0000000108a67288 clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::TraverseStmt(clang::Stmt*, llvm::SmallVectorImpl<llvm::PointerIntPair<clang::Stmt*, 1u, bool, llvm::PointerLikeTypeTraits<clang::Stmt*>, llvm::PointerIntPairInfo<clang::Stmt*, 1u, llvm::PointerLikeTypeTraits<clang::Stmt*>>>>*) + 672
14 libasm_debug.dylib       0x0000000108b4ef78 clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::TraverseFunctionHelper(clang::FunctionDecl*) + 1404
15 libasm_debug.dylib       0x0000000108a61c3c clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::TraverseFunctionDecl(clang::FunctionDecl*) + 128
16 libasm_debug.dylib       0x0000000108a58914 clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::TraverseDecl(clang::Decl*) + 2852
17 libasm_debug.dylib       0x0000000108ae473c clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::TraverseDeclContextHelper(clang::DeclContext*) + 216
18 libasm_debug.dylib       0x0000000108a6684c clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::TraverseTranslationUnitDecl(clang::TranslationUnitDecl*) + 564
19 libasm_debug.dylib       0x0000000108a58f14 clang::RecursiveASTVisitor<(anonymous namespace)::MyASTVisitor>::TraverseDecl(clang::Decl*) + 4388
20 libasm_debug.dylib       0x0000000108a57d8c (anonymous namespace)::MyASTConsumer::HandleTranslationUnit(clang::ASTContext&) + 52
21 libclang-cpp.dylib       0x00000001066383a8 clang::MultiplexConsumer::HandleTranslationUnit(clang::ASTContext&) + 52
22 libclang-cpp.dylib       0x0000000104911fa8 clang::ParseAST(clang::Sema&, bool, bool) + 752
23 libclang-cpp.dylib       0x00000001065ff750 clang::FrontendAction::Execute() + 112
24 libclang-cpp.dylib       0x0000000106582da8 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 868
25 libclang-cpp.dylib       0x0000000106677440 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 524
26 clang-16                 0x00000001004c2ca4 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) + 1464
27 clang-16                 0x00000001004bfb50 ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&) + 948
28 clang-16                 0x00000001004beddc clang_main(int, char**) + 11192
29 dyld                     0x0000000199750274 start + 2840
clang-16: error: unable to execute command: Segmentation fault: 11

编译命令

clang -Xclang -load -Xclang ./build/libasm_debug.dylib -Xclang -add-plugin -Xclang asm_debug testfile.c -target x86_64-apple-macos -fasm-blocks -g -O0

问题分析与解答

实现思路正确性

你的核心思路是可行的:通过RecursiveASTVisitor遍历AST定位MSAsmStmt,重写汇编内容插入.loc调试指令,这是给内联汇编补全调试信息的常规技术方向。但当前代码的问题在于对MSAsmStmt的源范围处理和Rewriter的使用细节。

段错误原因

从错误栈和代码来看,段错误的核心诱因是Rewriter::getRangeSize访问了无效内存,具体可能有以下几点:

  1. MSAsmStmt的源范围不适用直接替换
    MSAsmStmt的getBeginLoc()和getEndLoc()仅覆盖__asm关键字和外层大括号的范围,并非内部汇编指令的完整文本范围。Clang对MS风格汇编的源位置存储有特殊逻辑,直接用这个范围调用ReplaceText会导致Rewriter计算范围时访问无效内存区域。
  2. Rewriter初始化不完整
    如果插件中Rewriter未正确绑定ASTContext的SourceManager和LangOptions,调用getRangeSize时会因缺少源文件上下文而访问空指针,触发段错误。
  3. 汇编文本与源范围不匹配
    Asm->getAsmString()返回的是Clang解析后的标准化汇编字符串,和原始源代码中的文本格式、长度可能存在差异,直接替换会导致Rewriter计算范围时出现偏移错误。

修复建议

  1. 验证源范围有效性
    在调用ReplaceText前,添加以下代码确认源位置可访问:
    SourceManager &SM = Context->getSourceManager();
    if (!SM.isValidFileID(StartLoc.getFileID())) {
        llvm::errs() << "Invalid source location\n";
        return true;
    }
    // 打印位置偏移,确认范围合理
    llvm::errs() << "Start offset: " << SM.getFileOffset(StartLoc) << ", End offset: " << SM.getFileOffset(EndLoc) << "\n";
    
  2. 正确初始化Rewriter
    在ASTConsumer的Initialize方法中绑定SourceManager和LangOptions:
    void Initialize(ASTContext &Context) override {
        TheRewriter.setSourceMgr(Context.getSourceManager(), Context.getLangOpts());
    }
    
  3. 调整替换范围
    不要替换整个__asm块,而是只替换大括号内的汇编内容。可以通过手动定位大括号的位置,或者遍历MSAsmStmt的子节点获取内部指令的源范围。
  4. 使用CharSourceRange
    调用ReplaceText时,使用字符范围而非token范围,避免格式问题导致的计算错误:
    auto Range = CharSourceRange::getTokenRange(StartLoc, EndLoc);
    bool result = TheRewriter.ReplaceText(Range, AsmString);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:02:03