Even though the test app, golang and node apps (which use local TLS) work 
fine with this patch, the rust programs built as pies do not. Rust uses 
thread local heavily so one has to bump up the size of the TLS reservation 
in loader.ld.

Here is an example of a crash (seems to be in thread local code):

(gdb) bt
#0  0x00000000003a1b62 in processor::cli_hlt () at arch/x64/processor.hh:247
#1  arch::halt_no_interrupts () at arch/x64/arch.hh:48
#2  osv::halt () at arch/x64/power.cc:26
#3  0x000000000023efae in abort (fmt=fmt@entry=0x65a400 "general protection 
fault\n") at runtime.cc:132
#4  0x000000000039cf2a in general_protection () at 
arch/x64/exceptions.cc:322
#5  <signal handler called>
#6  0x6f57206f6c6c6548 in ?? ()
#7  0x0000100001408c6d in real_drop_in_place<alloc::boxed::Box<Write>> () 
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/ptr.rs:193
#8  real_drop_in_place<core::option::Option<alloc::boxed::Box<Write>>> () 
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/ptr.rs:193
#9  real_drop_in_place<core::cell::UnsafeCell<core::option::
Option<alloc::boxed::Box<Write>>>> () at /rustc/
fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/ptr.rs:193
#10 
real_drop_in_place<core::cell::RefCell<core::option::Option<alloc::boxed::Box<Write>>>>
 
() at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/ptr.rs:193
#11 real_drop_in_place<core::option::Option<core::cell::
RefCell<core::option::Option<alloc::boxed::Box<Write>>>>> () at /rustc/
fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/ptr.rs:193
*#12 
init<core::cell::RefCell<core::option::Option<alloc::boxed::Box<Write>>>> 
() at src/libstd/thread/local.rs:268 <http://local.rs:268/>*
#13 try_with<core::cell::RefCell<core::option::Option<alloc::
boxed::Box<Write>>>,closure,core::result::Result<(), 
std::io::error::Error>> () at src/libstd/thread/local.rs:302
#14 print_to<std::io::stdio::Stdout> () at src/libstd/io/stdio.rs:723
#15 _print () at src/libstd/io/stdio.rs:744
#16 0x0000100001404069 in hello::main ()
#17 0x00001000014041a3 in std::rt::lang_start::{{closure}} ()
#18 0x000010000140e663 in {{closure}} () at src/libstd/rt.rs:49
#19 do_call<closure,i32> () at src/libstd/panicking.rs:297
#20 0x000010000141054a in __rust_maybe_catch_panic () at 
src/libpanic_unwind/lib.rs:87
#21 0x000010000140f11d in try<i32,closure> () at src/libstd/panicking.rs:276
#22 catch_unwind<closure,i32> () at src/libstd/panic.rs:388
#23 lang_start_internal () at src/libstd/rt.rs:48
#24 0x0000100001404192 in main ()
#25 0x000000000042273d in osv::application::run_main() () at core/app.cc:417
#26 0x000000000042285f in __libc_start_main () at core/app.cc:37
#27 0x0000100001403e4a in _start ()

So I wonder if there is a gap in this patch.

Does anybody know of any non-rust app that uses TLS heavily? 

Waldek 

On Monday, May 6, 2019 at 12:51:05 AM UTC-4, Waldek Kozaczuk wrote:
>
> This patch enhances OSv dynamic loader to support 
> pies and position dependant executables that use TLS 
> (Thread Local Storage) in local-exec mode. 
>
> It does so by reserving an extra slot in kernel static 
> TLS block at its end and designating it as user static TLS 
> for the executable ELF. Any dependant ELF objects are still 
> places in the are before the kernel TLS. The specifics please 
> read comments added to arch-elf.cc and arch-switch.hh. 
>
> Please note that this solution limits the size of the application 
> ELF block to 64 bytes plus extra gap due to 64-bytes alignment 
> of the kernel TLS. This should be sufficient for most applications 
> which either use tiny TLS (Golang uses 8-bytes long) if at all. 
> Rust ELFs tend to rely on quite large TLS in which case the limit 
> in loader.ld needs to be increased accordingly and loader.elf 
> relinked. 
>
> Fixes #352 
>
> Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com> 
> --- 
>  arch/x64/arch-elf.cc    | 65 +++++++++++++++++++++++++++++++++++---- 
>  arch/x64/arch-elf.hh    |  2 +- 
>  arch/x64/arch-switch.hh | 68 +++++++++++++++++++++++++++++++++++------ 
>  arch/x64/loader.ld      |  4 +++ 
>  core/elf.cc             | 26 +++++++++++----- 
>  include/osv/elf.hh      |  7 +++-- 
>  modules/tests/Makefile  | 14 +++++++-- 
>  tests/libtls.cc         |  7 +++++ 
>  tests/tst-tls.cc        | 12 +++++--- 
>  9 files changed, 173 insertions(+), 32 deletions(-) 
>
> diff --git a/arch/x64/arch-elf.cc b/arch/x64/arch-elf.cc 
> index 82c60eb1..ffd98fe1 100644 
> --- a/arch/x64/arch-elf.cc 
> +++ b/arch/x64/arch-elf.cc 
> @@ -12,6 +12,8 @@ 
>   
>  namespace elf { 
>   
> +// This function is solely used to relocate symbols in OSv kernel ELF 
> +// and is indirectly called by loader premain() function 
>  bool arch_init_reloc_dyn(struct init_table *t, u32 type, u32 sym, 
>                           void *addr, void *base, Elf64_Sxword addend) 
>  { 
> @@ -33,7 +35,7 @@ bool arch_init_reloc_dyn(struct init_table *t, u32 type, 
> u32 sym, 
>      case R_X86_64_GLOB_DAT: 
>          *static_cast<u64*>(addr) = t->dyn_tabs.lookup(sym)->st_value; 
>          break; 
> -    case R_X86_64_DPTMOD64: 
> +    case R_X86_64_DTPMOD64: 
>          abort(); 
>          //*static_cast<u64*>(addr) = symbol_module(sym); 
>          break; 
> @@ -53,6 +55,10 @@ bool arch_init_reloc_dyn(struct init_table *t, u32 
> type, u32 sym, 
>      return true; 
>  } 
>   
> +// 
> +// This method is used when relocating symbols in all ELF objects 
> +// except for OSv kernel ELF itself which is relocated by 
> +// the function arch_init_reloc_dyn() above 
>  bool object::arch_relocate_rela(u32 type, u32 sym, void *addr, 
>                                  Elf64_Sxword addend) 
>  { 
> @@ -74,23 +80,58 @@ bool object::arch_relocate_rela(u32 type, u32 sym, 
> void *addr, 
>      case R_X86_64_GLOB_DAT: 
>          *static_cast<void**>(addr) = symbol(sym).relocated_addr(); 
>          break; 
> -    case R_X86_64_DPTMOD64: 
> +    // The next 3 types are intended to relocate symbols of thread local 
> variables 
> +    // defined with __thread modifier 
> +    // 
> +    // Please note that thread local variables accessed in so called 
> local-exec mode 
> +    // are never relocated as their negative offsets relative to the TCB 
> address in FS register, 
> +    // are placed by static linker into the final code as in this 
> example: 
> +    //    mov %fs:0xfffffffffffffffc,%eax 
> +    // 
> +    case R_X86_64_DTPMOD64: 
> +        // This type and next R_X86_64_DTPOFF64 are intended to prepare 
> execution of __tls_get_addr() 
> +        // which provides dynamic access of thread local variable 
> +        // This calculates the module index of the ELF containing the 
> variable 
>          if (sym == STN_UNDEF) { 
> +            // The thread-local variable being accessed is within 
> +            // the SAME shared object as the caller 
>              *static_cast<u64*>(addr) = _module_index; 
> +            // No need to calculate the offset to the beginning 
>          } else { 
> -            *static_cast<u64*>(addr) = symbol(sym).obj->_module_index; 
> +            // The thread-local variable being accessed is located 
> +            // in DIFFERENT shared object that the caller 
> +            *static_cast<u64*>(addr) = symbol(sym).obj->module_index(); 
>          } 
>          break; 
>      case R_X86_64_DTPOFF64: 
> +        // The thread-local variable being accessed is located 
> +        // in DIFFERENT shared object that the caller 
>          *static_cast<u64*>(addr) = symbol(sym).symbol->st_value; 
>          break; 
>      case R_X86_64_TPOFF64: 
> +        // This type is intended to resolve symbols of thread-local 
> variables in static TLS 
> +        // accessed in initial-exec mode and is handled to calculate the 
> virtual address of 
> +        // target thread-local variable 
>          if (sym) { 
>              auto sm = symbol(sym); 
> -            sm.obj->alloc_static_tls(); 
> -            auto tls_offset = sm.obj->static_tls_end() + 
> sched::kernel_tls_size(); 
> +            ulong tls_offset; 
> +            if (sm.obj->is_executable()) { 
> +                tls_offset = sm.obj->get_tls_size(); 
> +                // If this is an executable (pie or position-dependant 
> one) 
> +                // then the variable is located in the reserved slot of 
> the TLS 
> +                // right where the kernel TLS lives 
> +                // So the offset is negative size of this ELF TLS block 
> +            } else { 
> +                // If shared library, the variable is located in one of 
> TLS 
> +                // blocks that are part of the static TLS before kernel 
> part 
> +                // so the offset needs to shift by sum of kernel and size 
> of the user static 
> +                // TLS so far 
> +                sm.obj->alloc_static_tls(); 
> +                tls_offset = sm.obj->static_tls_end() + 
> sched::kernel_tls_size(); 
> +            } 
>              *static_cast<u64*>(addr) = sm.symbol->st_value + addend - 
> tls_offset; 
>          } else { 
> +            // TODO: Which case does this handle? 
>              alloc_static_tls(); 
>              auto tls_offset = static_tls_end() + 
> sched::kernel_tls_size(); 
>              *static_cast<u64*>(addr) = addend - tls_offset; 
> @@ -126,7 +167,19 @@ void object::prepare_initial_tls(void* buffer, size_t 
> size, 
>      memset(ptr + _tls_init_size, 0, _tls_uninit_size); 
>   
>      offsets.resize(std::max(_module_index + 1, offsets.size())); 
> -    offsets[_module_index] = - _static_tls_offset - tls_size - 
> sched::kernel_tls_size(); 
> +    auto offset = - _static_tls_offset - tls_size - 
> sched::kernel_tls_size(); 
> +    offsets[_module_index] = offset; 
> +} 
> + 
> +void object::prepare_local_tls(std::vector<ptrdiff_t>& offsets) 
> +{ 
> +    if (!_static_tls && !is_executable()) { 
> +        return; 
> +    } 
> + 
> +    offsets.resize(std::max(_module_index + 1, offsets.size())); 
> +    auto offset = - get_tls_size(); 
> +    offsets[_module_index] = offset; 
>  } 
>   
>  } 
> diff --git a/arch/x64/arch-elf.hh b/arch/x64/arch-elf.hh 
> index 2c347777..1811ceb5 100644 
> --- a/arch/x64/arch-elf.hh 
> +++ b/arch/x64/arch-elf.hh 
> @@ -18,7 +18,7 @@ enum { 
>      R_X86_64_PC16 = 13, //  word16 S + A - P 
>      R_X86_64_8 = 14, //  word8 S + A 
>      R_X86_64_PC8 = 15, //  word8 S + A - P 
> -    R_X86_64_DPTMOD64 = 16, //  word64 
> +    R_X86_64_DTPMOD64 = 16, //  word64 
>      R_X86_64_DTPOFF64 = 17, //  word64 
>      R_X86_64_TPOFF64 = 18, //  word64 
>      R_X86_64_TLSGD = 19, //  word32 
> diff --git a/arch/x64/arch-switch.hh b/arch/x64/arch-switch.hh 
> index 88bef949..cd1acb83 100644 
> --- a/arch/x64/arch-switch.hh 
> +++ b/arch/x64/arch-switch.hh 
> @@ -151,33 +151,83 @@ void thread::init_stack() 
>  } 
>   
>  void thread::setup_tcb() 
> -{ 
> -    assert(tls.size); 
> +{   // 
> +    // Most importantly this method allocates TLS memory region and 
> +    // sets up TCB (Thread Control Block) that points to that allocated 
> +    // memory region. The TLS memory region is designated to a specific 
> thread 
> +    // and holds thread local variables (with __thread modifier) defined 
> +    // in OSv kernel and the application ELF objects including dependant 
> ones 
> +    // through DT_NEEDED tag. 
> +    // 
> +    // Each ELF object and OSv kernel gets its own TLS block with offsets 
> +    // specified in DTV structure (the offsets get calculated as ELF is 
> loaded and symbols 
> +    // resolved before we get to this point). 
> +    // 
> +    // Because both OSv kernel and position-in-dependant (pie) or 
> position-dependant 
> +    // executable (non library) are compiled to use local-exec mode to 
> access the thread 
> +    // local variables, we need to setup the offsets and TLS blocks in a 
> special way 
> +    // to avoid any collisions. Specifically we define OSv TLS segment 
> +    // (see arch/x64/loader.ld for specifics) with an extra buffer at 
> +    // the end of the kernel TLS to accommodate TLS block of pies and 
> +    // position-dependant executables. 
> + 
> +    // (1) - TLS memory area layout with app shared library 
> +    // |-----|-----|-----|--------------|------| 
> +    // |SO_3 |SO_2 |SO_1 |KERNEL        |<NONE>| 
> +    // |-----|-----|-----|--------------|------| 
> + 
> +    // (2) - TLS memory area layout with pie or 
> +    // position dependant executable 
> +    //       |-----|-----|---------------------| 
> +    //       |SO_3 |SO_2 |KERNEL        | EXE  | 
> +    //       |-----|-----|--------------|------| 
> + 
> +    assert(sched::tls.size); 
>   
>      void* user_tls_data; 
>      size_t user_tls_size = 0; 
> +    void* executable_tls_data; 
> +    size_t executable_tls_size = 0; 
>      if (_app_runtime) { 
>          auto obj = _app_runtime->app.lib(); 
>          assert(obj); 
>          user_tls_size = obj->initial_tls_size(); 
>          user_tls_data = obj->initial_tls(); 
> +        if (obj->is_executable()) { 
> +           executable_tls_size = obj->get_tls_size(); 
> +           executable_tls_data = obj->get_tls_segment(); 
> +        } 
>      } 
>   
>      // In arch/x64/loader.ld, the TLS template segment is aligned to 64 
>      // bytes, and that's what the objects placed in it assume. So make 
>      // sure our copy is allocated with the same 64-byte alignment, and 
>      // verify that object::init_static_tls() ensured that user_tls_size 
> -    // also doesn't break this alignment . 
> -    assert(align_check(tls.size, (size_t)64)); 
> +    // also doesn't break this alignment. 
> +    auto kernel_tls_size = sched::tls.size; 
> +    assert(align_check(kernel_tls_size, (size_t)64)); 
>      assert(align_check(user_tls_size, (size_t)64)); 
> -    void* p = aligned_alloc(64, sched::tls.size + user_tls_size + 
> sizeof(*_tcb)); 
> + 
> +    auto total_tls_size = kernel_tls_size + user_tls_size; 
> +    void* p = aligned_alloc(64, total_tls_size + sizeof(*_tcb)); 
> +    // First goes user TLS data 
>      if (user_tls_size) { 
>          memcpy(p, user_tls_data, user_tls_size); 
>      } 
> -    memcpy(p + user_tls_size, sched::tls.start, sched::tls.filesize); 
> -    memset(p + user_tls_size + sched::tls.filesize, 0, 
> -           sched::tls.size - sched::tls.filesize); 
> -    _tcb = static_cast<thread_control_block*>(p + tls.size + 
> user_tls_size); 
> +    // Next goes kernel TLS data 
> +    auto kernel_tls_offset = user_tls_size; 
> +    memcpy(p + kernel_tls_offset, sched::tls.start, sched::tls.filesize); 
> +    memset(p + kernel_tls_offset + sched::tls.filesize, 0, 
> +           kernel_tls_size - sched::tls.filesize); 
> + 
> +    if (executable_tls_size) { 
> +        // If executable copy its TLS block data at the designated offset 
> +        // at the end of area as described in the ascii art for 
> executables 
> +        // TLS layout 
> +        auto executable_tls_offset = total_tls_size - 
> executable_tls_size; 
> +        memcpy(p + executable_tls_offset, executable_tls_data, 
> executable_tls_size); 
> +    } 
> +    _tcb = static_cast<thread_control_block*>(p + total_tls_size); 
>      _tcb->self = _tcb; 
>      _tcb->tls_base = p + user_tls_size; 
>   
> diff --git a/arch/x64/loader.ld b/arch/x64/loader.ld 
> index caae1f68..adad2ab3 100644 
> --- a/arch/x64/loader.ld 
> +++ b/arch/x64/loader.ld 
> @@ -81,7 +81,11 @@ SECTIONS 
>      .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } :tls :text 
>      .tbss : { 
>          *(.tbss .tbss.* .gnu.linkonce.tb.*) 
> +        _pie_static_tls_start = .; 
> +        /* This is a reserve intended for executables' (pie or non-pie) 
> TLS block */ 
> +        . = . + 64; 
>          . = ALIGN(64); 
> +        _pie_static_tls_end = .; 
>      } :tls :text 
>      .tls_template_size = SIZEOF(.tdata) + SIZEOF(.tbss); 
>      .bss : { *(.bss .bss.*) } :text 
> diff --git a/core/elf.cc b/core/elf.cc 
> index ca9226f6..0a2e2fcd 100644 
> --- a/core/elf.cc 
> +++ b/core/elf.cc 
> @@ -373,6 +373,7 @@ Elf64_Note::Elf64_Note(void *_base, char *str) 
>      } 
>  } 
>   
> +extern "C" char _pie_static_tls_start, _pie_static_tls_end; 
>  void object::load_segments() 
>  { 
>      for (unsigned i = 0; i < _ehdr.e_phnum; ++i) { 
> @@ -437,9 +438,13 @@ void object::load_segments() 
>      // As explained in issue #352, we currently don't correctly support 
> TLS 
>      // used in PIEs. 
>      if (_is_executable && _tls_segment) { 
> -        std::cout << "WARNING: " << pathname() << " is a PIE using TLS. 
> This " 
> -                  << "is currently unsupported (see issue #352). Link 
> with " 
> -                  << "'-shared' instead of '-pie'.\n"; 
> +        auto tls_size = _tls_init_size + _tls_uninit_size; 
> +        ulong pie_static_tls_maximum_size = &_pie_static_tls_end - 
> &_pie_static_tls_start; 
> +        if (tls_size > pie_static_tls_maximum_size) { 
> +            std::cout << "WARNING: " << pathname() << " is a PIE using 
> TLS of size " << tls_size 
> +                  << " which is greater than " << 
> pie_static_tls_maximum_size << " bytes limit. " 
> +                  << "Either increase the limit or link with '-shared' 
> instead of '-pie'.\n"; 
> +        } 
>      } 
>  } 
>   
> @@ -1047,9 +1052,9 @@ void object::init_static_tls() 
>          } 
>          static_tls |= obj->_static_tls; 
>          _initial_tls_size = std::max(_initial_tls_size, 
> obj->static_tls_end()); 
> -        // Align initial_tls_size to 64 bytes, to not break the 64-byte 
> -        // alignment of the TLS segment defined in loader.ld. 
> -        _initial_tls_size = align_up(_initial_tls_size, (size_t)64); 
> +        // Align initial_tls_size to 64 bytes, to not break the 64-byte 
> +        // alignment of the TLS segment defined in loader.ld. 
> +        _initial_tls_size = align_up(_initial_tls_size, (size_t)64); 
>      } 
>      if (!static_tls) { 
>          _initial_tls_size = 0; 
> @@ -1061,8 +1066,13 @@ void object::init_static_tls() 
>          if (obj->is_core()) { 
>              continue; 
>          } 
> -        obj->prepare_initial_tls(_initial_tls.get(), _initial_tls_size, 
> -                                 _initial_tls_offsets); 
> +        if (obj->is_executable()) { 
> +            obj->prepare_local_tls(_initial_tls_offsets); 
> +        } 
> +        else { 
> +            obj->prepare_initial_tls(_initial_tls.get(), 
> _initial_tls_size, 
> +                                     _initial_tls_offsets); 
> +        } 
>      } 
>  } 
>   
> diff --git a/include/osv/elf.hh b/include/osv/elf.hh 
> index 0f1792c7..720df733 100644 
> --- a/include/osv/elf.hh 
> +++ b/include/osv/elf.hh 
> @@ -362,7 +362,10 @@ public: 
>      void init_static_tls(); 
>      size_t initial_tls_size() { return _initial_tls_size; } 
>      void* initial_tls() { return _initial_tls.get(); } 
> +    void* get_tls_segment() { return _tls_segment; } 
>      std::vector<ptrdiff_t>& initial_tls_offsets() { return 
> _initial_tls_offsets; } 
> +    bool is_executable() { return _is_executable; } 
> +    ulong get_tls_size(); 
>  protected: 
>      virtual void load_segment(const Elf64_Phdr& segment) = 0; 
>      virtual void unload_segment(const Elf64_Phdr& segment) = 0; 
> @@ -387,9 +390,9 @@ private: 
>      void relocate_rela(); 
>      void relocate_pltgot(); 
>      unsigned symtab_len(); 
> -    ulong get_tls_size(); 
>      void collect_dependencies(std::unordered_set<elf::object*>& ds); 
>      void prepare_initial_tls(void* buffer, size_t size, 
> std::vector<ptrdiff_t>& offsets); 
> +    void prepare_local_tls(std::vector<ptrdiff_t>& offsets); 
>      void alloc_static_tls(); 
>      void make_text_writable(bool flag); 
>  protected: 
> @@ -434,7 +437,7 @@ protected: 
>                              Elf64_Sxword addend); 
>      bool arch_relocate_jump_slot(u32 sym, void *addr, Elf64_Sxword 
> addend, bool ignore_missing = false); 
>      size_t static_tls_end() { 
> -        if (is_core()) { 
> +        if (is_core() || is_executable()) { 
>              return 0; 
>          } 
>          return _static_tls_offset + get_tls_size(); 
> diff --git a/modules/tests/Makefile b/modules/tests/Makefile 
> index 5c94e549..a353d9e2 100644 
> --- a/modules/tests/Makefile 
> +++ b/modules/tests/Makefile 
> @@ -108,7 +108,7 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so 
> tst-bsd-evh.so \ 
>          tst-sendfile.so misc-lock-perf.so tst-uio.so tst-printf.so \ 
>          tst-pthread-affinity.so tst-pthread-tsd.so tst-thread-local.so \ 
>          tst-zfs-mount.so tst-regex.so tst-tcp-siocoutq.so \ 
> -        libtls.so tst-tls.so tst-select-timeout.so tst-faccessat.so \ 
> +        libtls.so tst-tls.so tst-tls-pie.so tst-select-timeout.so 
> tst-faccessat.so \ 
>          tst-fstatat.so misc-reboot.so tst-fcntl.so payload-namespace.so \ 
>          tst-namespace.so tst-without-namespace.so payload-env.so \ 
>          payload-merge-env.so misc-execve.so misc-execve-payload.so 
> misc-mutex2.so \ 
> @@ -139,7 +139,17 @@ $(out)/tests/tst-tls.so: \ 
>                  $(src)/tests/tst-tls.cc \ 
>                  $(out)/tests/libtls.so 
>          $(makedir) 
> -        $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -shared -o $@ $< 
> tests/libtls.so, CXX tst-tls.so) 
> +        $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -D__SHARED_OBJECT__=1 
> -shared -o $@ $< tests/libtls.so, CXX tst-tls.so) 
> + 
> +$(out)/tests/tst-tls-pie.o: CXXFLAGS:=$(subst -fPIC,-fpie,$(CXXFLAGS)) 
> +$(out)/tests/tst-tls-pie.o: $(src)/tests/tst-tls.cc 
> +        $(makedir) 
> +        $(call quiet, $(CXX) $(CXXFLAGS) -c -o $@ $<, CXX $*.cc) 
> +$(out)/tests/tst-tls-pie.so: \ 
> +                $(out)/tests/tst-tls-pie.o \ 
> +                $(out)/tests/libtls.so 
> +        $(makedir) 
> +        $(call quiet, cd $(out); $(CXX) $(CXXFLAGS) -fuse-ld=bfd -pthread 
> -pie -o $@ $< tests/libtls.so, LD tst-tls-pie.so) 
>   
>  boost-tests := tst-vfs.so tst-libc-locking.so misc-fs-stress.so \ 
>          misc-bdev-write.so misc-bdev-wlatency.so misc-bdev-rw.so \ 
> diff --git a/tests/libtls.cc b/tests/libtls.cc 
> index bf7e7e70..96e380e5 100644 
> --- a/tests/libtls.cc 
> +++ b/tests/libtls.cc 
> @@ -12,9 +12,16 @@ __thread int ex1 = 321; 
>  __thread int ex2 __attribute__ ((tls_model ("initial-exec"))) = 432; 
>  __thread int ex3 = 765; 
>   
> +extern __thread int v1; 
> +extern __thread int v5; 
> + 
>  void external_library() 
>  { 
> +    // ex1 and ex3 get accessed by _tls_get_addr() 
>      ex1++; 
>      ex2++; 
>      ex3++; 
> +    // These 2 below get handled by get _tls_get_addr() function in 
> core/elf.cc 
> +    v1++; 
> +    v5++; 
>  } 
> diff --git a/tests/tst-tls.cc b/tests/tst-tls.cc 
> index f827aa71..452052c2 100644 
> --- a/tests/tst-tls.cc 
> +++ b/tests/tst-tls.cc 
> @@ -37,7 +37,7 @@ static __thread int v6 __attribute__ ((tls_model 
> ("initial-exec"))) = 678; 
>   
>  extern __thread int ex3 __attribute__ ((tls_model ("initial-exec"))); 
>   
> -#ifndef __OSV__ 
> +#ifndef __SHARED_OBJECT__ 
>  // We can also try to force the "Local Exec" TLS model, but OSv's 
> makefile 
>  // builds all tests as shared objects (.so), and the linker will report 
> an 
>  // error, because local-exec is not allowed in shared libraries, just in 
> @@ -65,7 +65,7 @@ int main(int argc, char** argv) 
>      report(v5 == 567, "v5"); 
>      report(v6 == 678, "v6"); 
>      report(ex3 == 765, "ex3"); 
> -#ifndef __OSV__ 
> +#ifndef __SHARED_OBJECT__ 
>      report(v7 == 789, "v7"); 
>  #endif 
>   
> @@ -73,6 +73,8 @@ int main(int argc, char** argv) 
>      report(ex1 == 322, "ex1 modified"); 
>      report(ex2 == 433, "ex2 modified"); 
>      report(ex3 == 766, "ex3 modified"); 
> +    report(v1 == 124, "v1 modified"); 
> +    report(v5 == 568, "v5 modified"); 
>   
>      // Write on this thread's variables, and see a new thread gets 
>      // the original default values 
> @@ -82,7 +84,7 @@ int main(int argc, char** argv) 
>      v4 = 0; 
>      v5 = 0; 
>      v6 = 0; 
> -#ifndef __OSV__ 
> +#ifndef __SHARED_OBJECT__ 
>      v7 = 0; 
>  #endif 
>   
> @@ -97,7 +99,7 @@ int main(int argc, char** argv) 
>              report(v5 == 567, "v5 in new thread"); 
>              report(v6 == 678, "v6 in new thread"); 
>              report(ex3 == 765, "ex3 in new thread"); 
> -#ifndef __OSV__ 
> +#ifndef __SHARED_OBJECT__ 
>              report(v7 == 789, "v7 in new thread"); 
>  #endif 
>   
> @@ -105,6 +107,8 @@ int main(int argc, char** argv) 
>              report(ex1 == 322, "ex1 modified in new thread"); 
>              report(ex2 == 433, "ex2 modified in new thread"); 
>              report(ex3 == 766, "ex3 modified in new thread"); 
> +            report(v1 == 124, "v1 modified in new thread"); 
> +            report(v5 == 568, "v5 modified"); 
>      }); 
>      t1.join(); 
>   
> -- 
> 2.20.1 
>
>

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/adf27c32-1c93-4371-8deb-926f159263c1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to