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

iOS环境下在LLVM Bitcode中调用NSLog引发运行时错误

Fixing EXC_BAD_ACCESS When Calling NSLog From LLVM Pass for Bitcode-enabled Mach-O Files

Let's break down exactly why your code is crashing and walk through the fixes step by step. The EXC_BAD_ACCESS at objc_msgSend tells us NSLog is getting an invalid object pointer—your current code passes a raw C string instead of the NSString object NSLog expects, plus you've got the wrong calling convention and function signature for NSLog. Here's how to fix it:

1. Correct NSLog's Function Signature & Calling Convention

NSLog is an Objective-C function, not a Swift one. Its actual signature is:

void NSLog(NSString *format, ...);

We need to define the right function type and use the C calling convention (not Swift) since that's what Objective-C uses.

2. Convert Your C String to an NSString Object

CreateGlobalStringPtr generates a null-terminated C string, but NSLog requires an NSString instance. We'll use Objective-C runtime functions to convert the C string properly:

  • Fetch the NSString class with objc_getClass
  • Use sel_registerName to get the selector for stringWithUTF8String:
  • Call that selector on the NSString class to create our string object

3. Fix the NSLog Call

Pass the valid NSString object as the first argument to NSLog instead of the raw C string.

Modified LLVM Pass Code

// Get or declare NSLog with the correct signature
Function *Nslog = module->getFunction("NSLog");
if (!Nslog) {
    Type *VoidTy = Type::getVoidTy(module->getContext());
    PointerType *NSStringPtrTy = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
    // NSLog takes NSString* as first param, followed by variadic args
    FunctionType *FuncTy = FunctionType::get(VoidTy, {NSStringPtrTy}, true);
    Nslog = Function::Create(FuncTy, GlobalValue::ExternalLinkage, "NSLog", module);
    Nslog->setCallingConv(CallingConv::C); // Use C calling convention, not Swift
}

// Declare required Objective-C runtime functions if missing
Function *objc_getClass = module->getFunction("objc_getClass");
if (!objc_getClass) {
    PointerType *CharPtrTy = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
    FunctionType *ObjcGetClassTy = FunctionType::get(CharPtrTy, {CharPtrTy}, false);
    objc_getClass = Function::Create(ObjcGetClassTy, GlobalValue::ExternalLinkage, "objc_getClass", module);
    objc_getClass->setCallingConv(CallingConv::C);
}

Function *sel_registerName = module->getFunction("sel_registerName");
if (!sel_registerName) {
    PointerType *CharPtrTy = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
    FunctionType *SelRegNameTy = FunctionType::get(CharPtrTy, {CharPtrTy}, false);
    sel_registerName = Function::Create(SelRegNameTy, GlobalValue::ExternalLinkage, "sel_registerName", module);
    sel_registerName->setCallingConv(CallingConv::C);
}

Function *objc_msgSend = module->getFunction("objc_msgSend");
if (!objc_msgSend) {
    PointerType *IdTy = PointerType::get(IntegerType::get(module->getContext(), 8), 0);
    // objc_msgSend is variadic: returns id, takes id (receiver), SEL (selector), then args
    FunctionType *ObjcMsgSendTy = FunctionType::get(IdTy, {IdTy, IdTy}, true);
    objc_msgSend = Function::Create(ObjcMsgSendTy, GlobalValue::ExternalLinkage, "objc_msgSend", module);
    objc_msgSend->setCallingConv(CallingConv::C);
}

IRBuilder<> builder(module->getContext());
builder.SetInsertPoint(bb);

// Step 1: Create raw C string for the function name
llvm::Value *cFuncName = builder.CreateGlobalStringPtr(func_name);

// Step 2: Get the NSString class
llvm::Value *NSStringClassName = builder.CreateGlobalStringPtr("NSString");
llvm::Value *NSStringClass = builder.CreateCall(objc_getClass, {NSStringClassName});

// Step 3: Get the selector for stringWithUTF8String:
llvm::Value *selectorStr = builder.CreateGlobalStringPtr("stringWithUTF8String:");
llvm::Value *stringSelector = builder.CreateCall(sel_registerName, {selectorStr});

// Step 4: Convert C string to NSString
llvm::Value *nsFuncName = builder.CreateCall(objc_msgSend, {NSStringClass, stringSelector, cFuncName});

// Step 5: Call NSLog with the valid NSString
builder.CreateCall(Nslog, {nsFuncName});

Key Fixes Explained

  • Calling Convention: Switched from CallingConv::Swift to CallingConv::C—all Objective-C functions use the standard C calling convention, so this was a critical mismatch.
  • Valid NSString Object: We no longer pass a raw C string to NSLog. Instead, we properly construct an NSString using the Objective-C runtime, which gives NSLog a valid object pointer to work with.
  • Correct Function Signature: Fixed NSLog's type to return void and accept an NSString* as its first (variadic) parameter, matching its actual implementation.

Why the Original Code Crashed

Your original code passed a raw C string pointer to NSLog, which expects an NSString object. When NSLog tried to send Objective-C messages to this pointer (treating it as an object), it accessed invalid memory (hence the KERN_INVALID_ADDRESS at 0x1), triggering the segmentation fault.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 08:42:51