为 C++ 编译时未找到符号,但为 C 找到了符号

Posted

技术标签:

【中文标题】为 C++ 编译时未找到符号,但为 C 找到了符号【英文标题】:Symbols not found when compiling for C++, but found for C 【发布时间】:2014-08-07 23:59:43 【问题描述】:

我正在尝试在 C++ 下的 OS X 上编译一些代码,但我遇到了一些未找到符号的问题。

当我为 C 编译时,它工作得很好:

g++ -x c -fobjc-arc -fobjc-link-runtime -framework IOKit -framework CoreFoundation -framework Foundation kextstat/main.cpp -o ks

当我将-x c 更改为-x c++ 时,突然找不到符号:

$ g++ -x c++ -fobjc-arc -fobjc-link-runtime -framework IOKit -framework CoreFoundation -framework Foundation kextstat/main.cpp -o ks
Undefined symbols for architecture x86_64:
  "OSKextCopyLoadedKextInfo(__CFArray const*, __CFArray const*)", referenced from:
      _main in main-66ed7f.o
  "kas_info(int, void*, unsigned long*)", referenced from:
      print_kextstat(__CFDictionary const*) in main-66ed7f.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

我删除了对这些符号的引用并获得了 C++ 版本进行编译,以便我可以检查每个二进制文件链接的库是否存在不一致,但它们完全相同:

$ otool -L ks_cxx
ks_cxx:
    /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 855.17.0)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1056.13.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
$ otool -L ks_c
ks_c:
    /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 855.17.0)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1056.13.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

这是main.cpp的代码清单:

#import <CoreFoundation/CoreFoundation.h>

#define KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR (0)
#define KAS_INFO_MAX_SELECTOR (1)
int kas_info(int selector, void *value, size_t *size);
extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef);

// Convert a CFString to a standard C string
char* cstring(CFStringRef s) 
  return ((char*)CFStringGetCStringPtr(s, kCFStringEncodingMacRoman));


void print_kextstat(CFDictionaryRef dict) 
  size_t kaslr_size = 0;
  uint64_t kaslr_slide = 0;
  kaslr_size = sizeof(kaslr_slide);
  int ret = kas_info(KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR, &kaslr_slide, &kaslr_size);
  if (ret != 0) 
    printf("[ERROR] Could not get kernel ASLR slide info from kas_info(). Errno: %d\n", errno);
    exit(1);
  
  printf("[INFO] Kernel ASLR slide is 0x%llx\n", kaslr_slide);

  CFIndex count = CFDictionaryGetCount(dict);
  CFIndex i, j;

  void **keys;
  void **values;

  keys = (void **)malloc(sizeof(void *) * count);
  values = (void **)malloc(sizeof(void *) * count);

  CFDictionaryGetKeysAndValues(
    dict,
    (const void **)keys,
    (const void **)values
  );

  printf("Index Refs Address            Size         Wired        Name (Version) <Linked Against>\n");
  for (i = 0; i < count; i++) 
    for (j = 0; j < count; j++) 
      int kextTag;
      int refs;
      unsigned long long address;
      unsigned long long size;
      unsigned long long wired;

      char *name = cstring((CFStringRef)CFDictionaryGetValue((CFDictionaryRef)(values)[j], CFSTR("CFBundleIdentifier")));

      CFNumberGetValue(
        (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)values[j], CFSTR("OSBundleLoadTag")),
        kCFNumberSInt32Type,
        &kextTag
      );
      if (kextTag != i) 
        continue;
      
      CFNumberGetValue(
        (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)values[j], CFSTR("OSBundleRetainCount")),
        kCFNumberSInt32Type,
        &refs
      );
      CFNumberGetValue(
        (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)values[j], CFSTR("OSBundleLoadAddress")),
        kCFNumberSInt64Type,
        &address
      );
      CFNumberGetValue(
        (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)values[j], CFSTR("OSBundleLoadSize")),
        kCFNumberSInt64Type,
        &size
      );
      CFNumberGetValue(
        (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)values[j], CFSTR("OSBundleWiredSize")),
        kCFNumberSInt64Type,
        &wired
      );
      printf("%5d %4d 0x%-16llx 0x%-10llx 0x%-10llx %s (%s) ",
        kextTag,
        refs,
        address + kaslr_slide,
        size,
        wired,
        name,
        cstring((CFStringRef)CFDictionaryGetValue((CFDictionaryRef)values[j], CFSTR("CFBundleVersion")))
      );

      CFArrayRef linkedAgainst = (CFArrayRef)CFDictionaryGetValue(
        (CFDictionaryRef)values[j],
        CFSTR("OSBundleDependencies")
      );

      if (linkedAgainst == NULL) 
        printf("\n");
        continue;
      

      CFIndex linkedCount = CFArrayGetCount(linkedAgainst);
      int linked = 0;

      CFMutableArrayRef marray = CFArrayCreateMutableCopy(
        NULL,
        linkedCount,
        linkedAgainst
      );

      CFArraySortValues(
        marray,
        CFRangeMake(0, linkedCount),
        (CFComparatorFunction)CFNumberCompare,
        NULL
      );

      printf("<");
      int l;
      for (l = 0; l < linkedCount; l++) 
        CFNumberGetValue(
          (CFNumberRef)CFArrayGetValueAtIndex(marray, l),
          kCFNumberSInt32Type,
          &linked
        );

        if (l)  
          printf(" ");
        
        printf ("%d", linked);
      
      printf(">\n");
    
  


int main (int argc, char **argv) 
    if (getuid() != 0) 
        printf("[ERROR] Please run me as root!\n");
        exit(1);
    

    print_kextstat(OSKextCopyLoadedKextInfo(NULL, NULL));

【问题讨论】:

好像在某处丢失了extern "C" 【参考方案1】:

您需要 extern "C" 围绕与使用 C ABI(而不是 C++ ABI)编译的代码链接的符号:

extern "C" 
    int kas_info(int selector, void *value, size_t *size);
    CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef);

如果需要同时使用C和C++编译程序:

#ifdef __cplusplus
#define EXTERN_C_BEG extern "C" 
#define EXTERN_C_END 
#else
#define EXTERN_C_BEG
#define EXTERN_C_END
#endif

EXTERN_C_BEG
int kas_info(int selector, void *value, size_t *size);
CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef);
EXTERN_C_END

【讨论】:

以上是关于为 C++ 编译时未找到符号,但为 C 找到了符号的主要内容,如果未能解决你的问题,请参考以下文章

在 Xcode 项目中使用 C/C++ 库时未找到体系结构 x86_64 的符号

从 MS Visual C++ 编译器更改为英特尔 C++ 19.1 编译器时未解析的外部符号 __imp__fread

为 f2py 使用 C++ 源时未定义的符号

校招-c++

使用 MatLab dll 时出现 C++ 错误:找到一个或多个多重定义符号

在 C++ 中使用 boost:regex_error 时未定义符号?