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

时间:2014-08-07 23:59:44

标签: c++ c macos gcc g++

我试图在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));
}

1 个答案:

答案 0 :(得分:0)

对于与使用C ABI编译的代码(而不是C ++ ABI)链接的符号,需要extern "C"

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