https://sourceware.org/bugzilla/show_bug.cgi?id=16937

            Bug ID: 16937
           Summary: aarch64: issue about executable exporting TLS class
                    static member variable
           Product: binutils
           Version: 2.25 (HEAD)
            Status: NEW
          Severity: normal
          Priority: P2
         Component: ld
          Assignee: unassigned at sourceware dot org
          Reporter: jingyuuiuc at gmail dot com

I have a piece of code behaves wrong on aarch64. The scenario is that both
executable and shared library define a TLS class static member variable.

On aarch64, the executable exports the symbol to dynamic symbol stable
with GLOBAL DEFAULT attribute. When shared library is dlopened, dynamic loader
finds the symbol in executable's symbol table and binds to it. Thus
both dynamic library and executable share the same copy of this
variable, which is wrong.

It's generally not expected that the linker will export a symbol in the
executable's dynamic symbol table unless it sees a reference from a shared
library.


$ g++ var_exe.cc -ldl -o var
$ g++ -shared -fPIC var_l.cc -o libvar1.so
$ g++ -shared -fPIC var_l.cc -o libvar2.so

On aarch64:
$ ./var
exe: live += 5
exe: live = 5
Calling libentry in ./libvar1.so...
lib: live += 3
lib: live = 8
Calling libentry in ./libvar2.so...
lib: live += 3
lib: live = 11

$ readelf --dyn-syms -W var | grep _ZN3var4liveE
   11: 0000000000000000     4 TLS     GLOBAL DEFAULT   18 _ZN3var4liveE
$ readelf --dyn-syms -W libvar1.so | grep _ZN3var4liveE
   16: 0000000000000000     4 TLS     GLOBAL DEFAULT   16 _ZN3var4liveE
$ readelf --dyn-syms -W libvar2.so | grep _ZN3var4liveE
   16: 0000000000000000     4 TLS     GLOBAL DEFAULT   16 _ZN3var4liveE

On x86:
$ ./var
exe: live += 5
exe: live = 5
Calling libentry in ./libvar1.so...
lib: live += 3
lib: live = 3
Calling libentry in ./libvar2.so...
lib: live += 3
lib: live = 3

$ readelf --dyn-syms -W var | grep _ZN3var4liveE
$ readelf --dyn-syms -W libvar1.so | grep _ZN3var4liveE
   13: 0000000000000000     4 TLS     GLOBAL DEFAULT   16 _ZN3var4liveE
$ readelf --dyn-syms -W libvar2.so | grep _ZN3var4liveE
   13: 0000000000000000     4 TLS     GLOBAL DEFAULT   16 _ZN3var4liveE

============var.h:================
#include <pthread.h>

class var{
 public:
  var(){};
  static void output(const char* prefix) {
    printf("%s: live = %d\n", prefix, live);
  };
  static void inc(const char* prefix, int i) {
    printf("%s: live += %d\n", prefix, i);
    live += i;
  };
 private:
  static __thread int live;
};

============var_l.cc:===============
#include <pthread.h>
#include <stdio.h>
#include "var.h"

__thread int var::live=0;

extern "C" void libentry() {
  var libvar;
  libvar.inc("lib", 3);
  libvar.output("lib");
}

============var_exe.cc:=================
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include "var.h"

__thread int var::live=0;

void* load_lib_and_call(const char* libname) {
  void* handle = dlopen(libname, RTLD_LOCAL | RTLD_NOW);
  if (handle == NULL) {
    printf("Can not open shared library %s\n", libname);
    return 0;
   }
   typedef void (*lib_fun_t)();
   lib_fun_t lib_entry_ = (lib_fun_t)(dlsym(handle, "libentry"));
   const char *dlsym_error = dlerror();
   if (dlsym_error) {
     printf("Can not load symbol libentry: %s\n", dlsym_error);
     dlclose(handle);
     return 0;
   }
   printf("Calling libentry in %s...\n", libname);
   lib_entry_();

   return handle;
}

int main() {
  var mainvar;
  mainvar.inc("exe", 5);
  mainvar.output("exe");

  void* handle1 = load_lib_and_call("./libvar1.so");
  void* handle2 = load_lib_and_call("./libvar2.so");

  if (handle1)
    dlclose(handle1);
  if (handle2)
    dlclose(handle2);

  return 0;
}

-- 
You are receiving this mail because:
You are on the CC list for the bug.

_______________________________________________
bug-binutils mailing list
bug-binutils@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-binutils

Reply via email to