···3131#include "ld.h"
3232#include "UndefinedFunction.h"
3333#include "Trampoline.h"
3434+#include "FileMap.h"
34353536class MachOLoader
3637{
···8788 // Performs pending binds. Used when loading the main executable and its dependencies.
8889 void doPendingBinds();
89909191+ void doPendingTLS();
9292+9393+ // Processes information from MachO and calls the TLS infrastructure to set things up
9494+ void setupTLS(const MachO& mach, const FileMap::ImageMap* img, intptr slide);
9595+9096 // Starts an application
9197 void run(MachO& mach, int argc, char** argv, char** envp, bool bindLazy = false);
9298···135141 bool bindLazy;
136142 };
137143 std::vector<PendingBind> m_pendingBinds;
144144+145145+ // Pending TLS variables
146146+ // Because of initializers, we need to run them after the binds are done
147147+ struct PendingTLS
148148+ {
149149+ const MachO* mach;
150150+ const FileMap::ImageMap* img;
151151+ intptr slide;
152152+ };
153153+ std::vector<PendingTLS> m_pendingTLS;
138154139155 std::vector<std::string> m_rpathContext;
140156 std::stack<std::string> m_loaderPath;
+182
src/dyld/TLS.cpp
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2013 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#include "TLS.h"
2121+#include <cstdlib>
2222+#include <map>
2323+#include <cassert>
2424+#include <cstring>
2525+#include "log.h"
2626+#include "trace.h"
2727+#include "mutex.h"
2828+2929+static void TLSRunDestructors(void* p);
3030+3131+static std::map<void*, Darling::ImageData*> m_images;
3232+static std::map<pthread_key_t, Darling::ImageData*> m_imagesKey;
3333+static Darling::Mutex m_imagesMutex;
3434+3535+// Maybe not a nice solution, we could implement TLS completely on our own via the fs/gs register
3636+static __thread Darling::ThreadData m_tlsData[1024]; // 1024 = PTHREAD_KEYS_MAX
3737+3838+// Used for a thread-local list of destructor-object pairs (DestructorLinkedListElement)
3939+static pthread_key_t m_keyDestructors;
4040+4141+__attribute__((constructor))
4242+ static void TLSSetupDestructors()
4343+{
4444+ pthread_key_create(&m_keyDestructors, TLSRunDestructors);
4545+}
4646+4747+static void TLSRunDestructors(void* p)
4848+{
4949+ TRACE1(p);
5050+5151+ Darling::DestructorLinkedListElement* dlist = static_cast<Darling::DestructorLinkedListElement*>(p);
5252+5353+ dlist = dlist->first;
5454+5555+ do
5656+ {
5757+ Darling::DestructorLinkedListElement* dthis = dlist;
5858+5959+ dlist->destructor(dlist->object);
6060+ dlist = dlist->next;
6161+6262+ delete dthis;
6363+ }
6464+ while (dlist != nullptr);
6565+}
6666+6767+__attribute__((naked)) void* Darling::TLSGetNative()
6868+{
6969+ return m_tlsData;
7070+}
7171+7272+void Darling::TLSSetup(void* imageKey, std::vector<tlv_descriptor*>& descriptors, std::vector<void*>& initializers, void* start, uintptr_t length)
7373+{
7474+ Darling::MutexLock _l(&m_imagesMutex);
7575+ pthread_key_t key;
7676+ ImageData* id;
7777+7878+ auto it = m_images.find(imageKey);
7979+ assert (it == m_images.end());
8080+8181+ pthread_key_create(&key, (void (*)(void *)) Darling::TLSTeardownThread);
8282+8383+ m_images[imageKey] = id = new ImageData{ key, start, length, initializers };
8484+ m_imagesKey[key] = id;
8585+8686+ for (tlv_descriptor* d : descriptors)
8787+ {
8888+ d->thunk = Darling::TLSGetAddr;
8989+ d->key = key;
9090+ }
9191+}
9292+9393+void Darling::TLSTeardown(void* imageKey)
9494+{
9595+ TRACE1(imageKey);
9696+9797+ Darling::MutexLock _l(&m_imagesMutex);
9898+ auto it = m_images.find(imageKey);
9999+ pthread_key_t key;
100100+101101+ assert(it != m_images.end());
102102+ key = it->second->key;
103103+104104+ // TODO: What to do with live objects with C++11 destructors? Does Apple's dyld handle this?
105105+106106+ m_imagesKey.erase(key);
107107+ pthread_key_delete(key);
108108+109109+ delete it->second;
110110+ m_images.erase(it);
111111+}
112112+113113+void Darling::TLSTeardownThread(Darling::ThreadData data)
114114+{
115115+ TRACE1((void*) data);
116116+ delete [] data;
117117+}
118118+119119+void* Darling::TLSAllocate(pthread_key_t key)
120120+{
121121+ TRACE1(key);
122122+123123+ Darling::MutexLock _l(&m_imagesMutex);
124124+125125+ Darling::ImageData* id = m_imagesKey[key];
126126+ char* data;
127127+128128+ assert(!m_tlsData[key]);
129129+130130+ // Allocate a new block for TLS variables
131131+ m_tlsData[key] = data = new char[id->length];
132132+133133+ // Copy the initial variable values into the new block
134134+ memcpy(data, id->start, id->length);
135135+136136+ // Run initializers (constructors etc.)
137137+ for (auto it = id->initializers.rbegin(); it != id->initializers.rend(); it++)
138138+ {
139139+ typedef void (*Initializer)();
140140+ Initializer in = Initializer(*it);
141141+ in();
142142+ }
143143+144144+ // Delete the data upon thread exit
145145+ pthread_setspecific(key, data);
146146+147147+ LOG << "TLS data allocated at " << (void*)data << std::endl;
148148+ LOG << "Pointer written at " << &m_tlsData[key] << std::endl;
149149+150150+ return data;
151151+}
152152+153153+void Darling::TLSAtExit(void (*destructor)(void*), void* object)
154154+{
155155+ TRACE2(destructor, object);
156156+157157+ Darling::DestructorLinkedListElement* last = static_cast<Darling::DestructorLinkedListElement*>(pthread_getspecific(m_keyDestructors));
158158+ Darling::DestructorLinkedListElement* d = new Darling::DestructorLinkedListElement;
159159+160160+ d->destructor = destructor;
161161+ d->object = object;
162162+ d->next = nullptr;
163163+164164+ if (last != nullptr)
165165+ {
166166+ d->first = last->first;
167167+ last->next = d;
168168+ }
169169+ else
170170+ {
171171+ d->first = d;
172172+ }
173173+174174+ pthread_setspecific(m_keyDestructors, d);
175175+}
176176+177177+void* Darling::TLSBootstrap(tlv_descriptor* desc)
178178+{
179179+ LOG << "Darling::TLSBootstrap() called, this should never happen\n";
180180+ abort();
181181+}
182182+
+78
src/dyld/TLS.h
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2013 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#ifndef TLS_H
2121+#define TLS_H
2222+#include "../libmach-o/MachO.h"
2323+#include <vector>
2424+#include <set>
2525+#include <pthread.h>
2626+#include <stdint.h>
2727+2828+namespace Darling
2929+{
3030+ typedef char* ThreadData;
3131+3232+ struct ImageData
3333+ {
3434+ pthread_key_t key;
3535+3636+ // Location of initial variable values
3737+ void* start;
3838+ uintptr_t length;
3939+4040+ std::vector<void*> initializers;
4141+ };
4242+4343+ struct DestructorLinkedListElement
4444+ {
4545+ void (*destructor)(void*);
4646+ void* object;
4747+ DestructorLinkedListElement *next, *first;
4848+ };
4949+5050+ // Called upon image load
5151+ void TLSSetup(void* key, std::vector<tlv_descriptor*>& descriptors, std::vector<void*>& initializers, void* start, uintptr_t length);
5252+5353+ // Called upon image unload
5454+ void TLSTeardown(void* key);
5555+5656+ // Called by pthread upon thread destruction
5757+ void TLSTeardownThread(ThreadData data);
5858+5959+ // Fast-path helper for darling_tls_get_addr()
6060+ void* TLSGetNative() asm("darling_tls_get_native");
6161+6262+ // Called by darling_tls_get_addr() when the variable is accessed for the first time - slow path
6363+ void* TLSAllocate(pthread_key_t key) asm("darling_tls_allocate");
6464+6565+ // Called by object initializers to register a destructor
6666+ void TLSAtExit(void (*destructor)(void*), void* object) asm("_tlv_atexit");
6767+6868+ // If this gets called, then the image wasn't initialized properly
6969+ void* TLSBootstrap(tlv_descriptor* desc) asm("_tlv_bootstrap");
7070+7171+ // Implemented in assembly
7272+ void* TLSGetAddr(tlv_descriptor* desc) asm("darling_tls_get_addr");
7373+7474+7575+}
7676+7777+#endif
7878+
+16-2
src/dyld/ld.cpp
···622622623623 while (it != le.end())
624624 {
625625- const Exports* e = *it;
626626- Exports::const_iterator itSym = e->find(symbol);
625625+ Exports* e = *it;
626626+ Exports::iterator itSym = e->find(symbol);
627627628628 if (itSym == e->end())
629629 itSym = e->find(std::string("_") + symbol); // TODO: WTF?
···631631 if (itSym != e->end())
632632 {
633633 if (handle != __DARLING_RTLD_STRONG || !(itSym->second.flag & 4))
634634+ {
635635+ MachO::Export& exp = itSym->second;
636636+637637+ // If there is a resolver function, we lazily call it now
638638+ // and update the original stub address with the real one returned.
639639+640640+ if (exp.resolver)
641641+ {
642642+ typedef uintptr_t (ResolverFunc)();
643643+ ResolverFunc* func = (ResolverFunc*) exp.resolver;
644644+ exp.addr = func();
645645+ exp.resolver = 0;
646646+ }
634647 return reinterpret_cast<void*>(itSym->second.addr);
648648+ }
635649 }
636650 it++;
637651 }
+114
src/dyld/tls_helper.nasm
···11+;
22+; This file is part of Darling.
33+;
44+; Copyright (C) 2013 Lubos Dolezel
55+;
66+; Darling is free software: you can redistribute it and/or modify
77+; it under the terms of the GNU General Public License as published by
88+; the Free Software Foundation, either version 3 of the License, or
99+; (at your option) any later version.
1010+;
1111+; Darling is distributed in the hope that it will be useful,
1212+; but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+; GNU General Public License for more details.
1515+;
1616+; You should have received a copy of the GNU General Public License
1717+; along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+;
1919+2020+2121+section .note.GNU-stack noalloc noexec nowrite progbits
2222+2323+extern darling_tls_get_native
2424+extern darling_tls_allocate
2525+2626+global darling_tls_get_addr
2727+2828+%ifidn __OUTPUT_FORMAT__, elf64
2929+3030+BITS 64
3131+section text
3232+3333+darling_tls_get_addr:
3434+ call darling_tls_get_native ; fast three-instruction function
3535+3636+ push rdi
3737+ mov rdi, [rdi+8]
3838+ mov rax, [rax+rdi*8]
3939+ pop rdi
4040+4141+ test rax, rax
4242+ jz slow_path
4343+4444+ add rax, [rdi+16] ; add the variable offset
4545+ ret
4646+4747+slow_path:
4848+ enter 592, 0
4949+5050+ ; Do a register full-save, because the caller assumes that no registers
5151+ ; except for rax/rdi will be modified
5252+ mov [rbp-8], rdi
5353+ mov [rbp-16], rsi
5454+ mov [rbp-24], rdx
5555+ mov [rbp-32], rcx
5656+ mov [rbp-40], r8
5757+ mov [rbp-48], r9
5858+ mov [rbp-56], r10
5959+ mov [rbp-64], r11
6060+ fxsave [rbp-592]
6161+6262+ mov rdi, [rdi+8] ; pass the pthread_key
6363+ call darling_tls_allocate
6464+6565+ fxrstor [rbp-592]
6666+ mov r11, [rbp-64]
6767+ mov r10, [rbp-56]
6868+ mov r9, [rbp-48]
6969+ mov r8, [rbp-40]
7070+ mov rcx, [rbp-32]
7171+ mov rdx, [rbp-24]
7272+ mov rsi, [rbp-16]
7373+ mov rdi, [rbp-8]
7474+7575+ add rax, [rdi+16] ; add the variable offset
7676+ leave
7777+ ret
7878+7979+%elifidn __OUTPUT_FORMAT__, elf
8080+8181+BITS 32
8282+section text
8383+8484+darling_tls_get_addr:
8585+ mov ecx, eax ; eax will get destroyed
8686+ call darling_tls_get_native ; fast three-instruction function
8787+ push ecx
8888+8989+ mov ecx, [ecx+4] ; add the pthread key
9090+ mov eax, [eax+ecx*4] ; read the value at the key
9191+9292+ test eax, eax
9393+ jz slow_path
9494+9595+ pop ecx
9696+ add eax, [ecx+8] ; add the offset
9797+ ret
9898+9999+slow_path:
100100+ mov ecx, [esp]
101101+ push dword [ecx+4] ; pass the pthread_key
102102+ call darling_tls_allocate
103103+ pop ecx
104104+ pop ecx
105105+106106+ add eax, [ecx+8] ; add the offset
107107+ ret
108108+109109+%else
110110+111111+%error "Unsupported platform"
112112+113113+%endif
114114+