Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does LLVM/Clang support the 'weak' attribute for weak linking?

In brief: does LLVM/Clang support the 'weak' attribute?

I'm learning some Arduino library sources (HardwareSerial.cpp to be more detailed) and I've found some interesting attribute weak that I've never used before:

#if defined(HAVE_HWSERIAL0)
  void serialEvent() __attribute__((weak));
  bool Serial0_available() __attribute__((weak));
#endif

I've found it interesting and I've read that the linker should set it to NULL if it's not defined.

However, in my tests with Clang I'm unable to use it.

File lib.cpp:

#include "lib.h"
#include <stdio.h>

void my_weak_func() __attribute__((weak));

void lib_func() {
    printf("lib_func()\n");

    if (my_weak_func)
        my_weak_func();
}

File lib.h:

#ifndef LIB_FUNC
#define LIB_FUNC

void lib_func();

#endif

File main.cpp:

#include "lib.h"
#include <stdio.h>

#ifdef DEFINE_WEAK
void my_weak_func() {
    printf("my_weak_func()\n");
}
#endif

int main() {

    lib_func();

    printf("finished\n");
    return 0;
}

If I use g++ lib.cpp main.cpp -o main -DDEFINE_WEAK I'm able to use it:

MBA-Anton:Weak_issue asmirnov$ ./main
lib_func()
my_weak_func()
finished

But if I use g++ lib.cpp main.cpp -o main I'm unable to link the application:

Undefined symbols for architecture x86_64:
  "my_weak_func()", referenced from:
      lib_func() in lib-ceb555.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

To be more detailed about Clang:

MBA-Anton:Weak_issue asmirnov$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

What should I do? Is the weak attribute supported by LLVM/Clang?

PS. I've already tried to rewrite lib.cpp in the way Apple describes and still get the same linker error:

#include "lib.h"
#include <stdio.h>

extern void my_weak_func() __attribute__((weak_import));

void lib_func() {
    printf("lib_func()\n");

    if (my_weak_func != NULL)
        my_weak_func();
}
like image 802
4ntoine Avatar asked Oct 01 '15 05:10

4ntoine


People also ask

Does LLVM use clang?

Clang operates in tandem with the LLVM compiler back end and has been a subproject of LLVM 2.6 and later. As with LLVM, it is free and open-source software under the Apache License 2.0 software license. Its contributors include Apple, Microsoft, Google, ARM, Sony, Intel, and AMD.

Is LLVM same as clang?

LLVM is a backend compiler meant to build compilers on top of it. It deals with optimizations and production of code adapted to the target architecture. CLang is a front end which parses C, C++ and Objective C code and translates it into a representation suitable for LLVM.

Which linker does clang use?

Clang can be configured to use one of several different linkers: GNU ld. GNU gold. LLVM's lld.

Is clang better than GCC?

Clang is much faster and uses far less memory than GCC. Clang aims to provide extremely clear and concise diagnostics (error and warning messages), and includes support for expressive diagnostics. GCC's warnings are sometimes acceptable, but are often confusing and it does not support expressive diagnostics.


1 Answers

It fails by design because the linker doesn't have enough information. Specifically, it doesn't work because of a combination of two default linker settings:

-two_levelnamespace

-two_levelnamespace instructs the linker to bind external symbols both by name and by library install path. When used, the linker associates symbols to libraries based on where it finds them at link-time, given the set of libraries that it was passed. If the linker doesn't find the symbol, then it won't know which library it came from.

You can turn off two-level namespacing with -flat_namespace, but in general, I think that it's a good practice to leave it on.

Linux's ld.so does not support two-level namespacing, so this is not a problem. Every undefined symbol is assumed to have a definition in some library, to be discovered at runtime.

-undefined error

The -undefined setting determines how to handle symbols that have no definition visible at link-time, and the default is to error out. The other sensible option is dynamic_lookup, which tells the dynamic linker to figure out where the symbol is on its own.


Changing either of these settings will solve your problem, but it is heavy-handed. You can also tell the linker to use dynamic lookup for specific symbols and keep the default to error by passing -U _my_weak_func to ld, or -Wl,-U,_my_weak_func to Clang (which tells it to pass it forward to the linker). The _ symbol name prefix is necessary.

You can craft a tbd file and use it in place of dynamic libraries to tell the linker exactly where a weak symbol would be found if it was implemented instead of forcing weak functions to use dynamic lookup. Apple uses tbd files for its libraries and frameworks, which is what allows weak linking to work. The process is somewhat tedious, though, because Apple doesn't offer tools to automatically create tbd files for libraries. You'd need to pass a file of the following format as a library to the compiler:

--- !tapi-tbd-v3
archs:           [ $ARCH ]
uuids:           [ '$ARCH: $UUID' ]
platform:        $ARCH
install-name:    $INSTALL_PATH
current-version: $CURRENT_VERSION
objc-constraint: none
exports:         
  - archs:           [ $ARCH ]
    symbols:         [ _my_weak_func ]
...

Where:

  • $ARCH is the architecture name of the thing you want to build (like "x86_64", without quotes)
  • $UUID can be queried with otool -l $path_to_your_lib | grep -A 2 LC_UUID
  • $INSTALL_PATH and $CURRENT_VERSION can be queried with otool -l $path_to_your_lib | grep -A 4 LC_ID_DYLIB

This will let the linker know which library should contain your weak symbol.

like image 171
zneak Avatar answered Oct 13 '22 17:10

zneak