Skip to content

Commit

Permalink
Support thread local storage
Browse files Browse the repository at this point in the history
Generally adds support to declare variables as thread_local

- Add support in HBRT start assembly to skip adjusting TLS relocations
- Add support in linker to generate tagged TLS entries
- Update linker to process TLS relocations correctly
- Update TLS code to ignore top half of module ID
- Update module images to hold a "module ID"
- Update custome linker to update module ID during binary link
- Update TLS code to track TLS sections via module ID

Change-Id: I1589550d7787beb08827ca24a728397dedf0373b
RTC: 147599
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/71709
Reviewed-by: Ilya Smirnov <ismirno@us.ibm.com>
Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
  • Loading branch information
popfuture authored and dcrowell77 committed Mar 11, 2019
1 parent 676c584 commit f547589
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 55 deletions.
123 changes: 118 additions & 5 deletions src/build/linker/linker.C
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
/* Contributors Listed Below - COPYRIGHT 2011,2018 */
/* Contributors Listed Below - COPYRIGHT 2011,2019 */
/* [+] International Business Machines Corp. */
/* [+] Jan Hlavac */
/* */
Expand Down Expand Up @@ -132,6 +132,10 @@ struct Object
FILE * iv_output; //!< output file handle
ssize_t tls_module; //!< module id of this module's
// thread local storage.
map<uint64_t,string> tls_vars; //!< keep track of TLS variables in
// this module by mapping offsets
// to names for use with identifying
// unnamed DTPRELs
/**
* Read the object from it's file and extract bfd, text, & data image
* @param[in] i_file : file path
Expand Down Expand Up @@ -219,7 +223,7 @@ inline bool Object::isELF()
}

/**
* Infomraiton needed to build the Module table in each output image
* Information needed to build the Module table in each output image
*/
class ModuleTable
{
Expand Down Expand Up @@ -289,11 +293,24 @@ vector<ModuleTable> module_tables;
map<string,size_t> weak_symbols;
set<string> all_symbols;
set<string> weak_symbols_to_check;

// map TLS symbol names to TLS module IDs
map<string, uint64_t> tls_modules;

// map TLS symbol names to TLS offsets
map<string, uint64_t> tls_offsets;

bool includes_extended_image = false;
bool relocation = true;

size_t next_tls_id = 0;

/**
* @brief Marker (ASCII 'TLS' + 0x00) or'd into bit 0 position of a TLS module
* relocation to flag it as such for runtime relocation processing
*/
const uint64_t TLS_MARKER = 0x544C530000000000ULL;

//-----------------------------------------------------------------------------
// MAIN
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -612,6 +629,38 @@ bool Object::write_object()
cout << strerror(error) << endl;
}

// Look for the "TLS_MODULE_ID" symbol in the module. If found, seek to
// its location in the final binary and update it with the TLS module ID
// for this module.
if (symbols.find(VFS_TOSTRING(TLS_MODULE_ID)) != symbols.end())
{
fseek(iv_output, symbols[VFS_TOSTRING(TLS_MODULE_ID)].address
+ offset + data.vma_offset, SEEK_SET);
size_t tlsModuleId = 0;
bfd_putb64(get_tls_module(),&tlsModuleId);
if (sizeof(tlsModuleId) != fwrite(&tlsModuleId, sizeof(uint8_t),
sizeof(tlsModuleId), iv_output))
{
const int error = errno;
cout << "Error writing TLS_MODULE_ID to output: " << endl;
cout << strerror(error) << endl;
}
else
{
cout << "Setting module ID to " << get_tls_module() << " for "
<< name << " addr = "
<< symbols[VFS_TOSTRING(TLS_MODULE_ID)].address
<< " + " << offset + data.vma_offset << endl;
}

// Seek back to where the cursor would have been, had the module
// ID not been updated
fseek(iv_output, offset + data.vma_offset + data.size, SEEK_SET);
}
else
{
cout << " module ID not found for " << name << endl;
}
}
else // binary blob
{
Expand Down Expand Up @@ -690,11 +739,27 @@ bool Object::read_relocation()
cout << "\tSymbol: " << syms[i]->name << endl;
cout << "\t\tAddress: " << std::hex << syms[i]->value << endl;

bool is_tls = false;

// Determine symbol types.
if (syms[i]->flags & BSF_THREAD_LOCAL)
{
cout << "\t\tTLS_VARIABLE" << endl;
is_tls = true;
}

if (syms[i]->flags & BSF_GLOBAL)
{
s.type |= Symbol::GLOBAL;
cout << "\t\tGLOBAL" << endl;
cout << "\t\tGLOBAL";
if (is_tls)
{
cout << " TLS offset: " << bfd_asymbol_value(syms[i]);

// store the name in a map of offsets to TLS variable names
tls_vars[bfd_asymbol_value(syms[i])] = s.name;
}
cout << endl;
}
else if (syms[i]->flags & (BSF_LOCAL | BSF_WEAK | BSF_GNU_UNIQUE))
{
Expand Down Expand Up @@ -827,10 +892,19 @@ bool Object::perform_local_relocations()

bool needs_relocation = true;

bool is_weak = false;

fseek(iv_output, offset + i->address, SEEK_SET);
fread(data, sizeof(uint64_t), 1, iv_output);

if (weak_symbols.find(i->name) != weak_symbols.end())
{
cout << "\t\tWEAK" << endl;
is_weak = true;
}

address = bfd_getb64(data);

if ((address != i->addend) && (address != 0))
{
ostringstream oss;
Expand All @@ -855,13 +929,25 @@ bool Object::perform_local_relocations()
address = get_tls_module();
needs_relocation = false;
relocation = address;

cout << "\t\tTLS_MODULE" << endl;
}
else if (i->type & Symbol::TLS_OFFSET)
{
// Set value to TLS offset.
address = i->addend - VFS_PPC64_DTPREL_OFFSET;
cout << "\t\tTLS_OFFSET" << endl;
address = relocation = i->addend - VFS_PPC64_DTPREL_OFFSET;
needs_relocation = false;
relocation = address;

// look up the offset in tls_vars find the name and use that
// to map the name to the correct TLS offset
tls_offsets[tls_vars[i->addend]] = relocation;
tls_modules[tls_vars[i->addend]] = get_tls_module();
}
else if (is_weak && address == 0)
{
cout << "\tWEAK NULL" << endl;
relocation = 0;
}
else // Perform relocation.
{
Expand Down Expand Up @@ -956,6 +1042,12 @@ bool Object::perform_global_relocations()
}
else
{
bool is_tls = false;
if (tls_modules.find(i->name) != tls_modules.end())
{
is_tls = true;
}

if (s.type & Symbol::FUNCTION)
{
cout << "\tTOC link for function: " << s.name
Expand All @@ -966,7 +1058,28 @@ bool Object::perform_global_relocations()
cout << "\tOffset to " << i->addend << endl;
symbol_addr += i->addend;
}

symbol_addr += j->base_addr;

if (is_tls)
{
if (i->type & Symbol::TLS_MODULE)
{
symbol_addr = tls_modules[i->name];

// Bitwise OR the TLS marker into the relocation
// to flag it as a TLS module entry for
// relocation processing code. This is safe
// since it would take 4 giga-modules to over
// flow into that space.
symbol_addr |= TLS_MARKER;
}
else if (i->type & Symbol::TLS_OFFSET)
{
symbol_addr = tls_offsets[i->name];
}
}

bfd_putb64(symbol_addr, data);
fseek(iv_output, offset + i->address, SEEK_SET);
fwrite(data, sizeof(uint64_t), 1, iv_output);
Expand Down
115 changes: 115 additions & 0 deletions src/include/util/nolockfree/stack.H
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
/* $Source: src/include/util/nolockfree/stack.H $ */
/* */
/* OpenPOWER HostBoot Project */
/* */
/* Contributors Listed Below - COPYRIGHT 2010,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
/* implied. See the License for the specific language governing */
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */

#ifndef __UTIL_NOLOCKFREE_STACK_H
#define __UTIL_NOLOCKFREE_STACK_H

#include <stddef.h>
#include <assert.h>

namespace Util
{
namespace NoLockFree
{

/**
* @brief Non-lockfree stack implementation
*
* This is an intrusive container design, meaning elements being
* added to the stack must have a 'next' member of _T* type. This
* container is not threadsafe.
*
* @note: For a lockfree stack implementation, see Util::LockFree::Stack
*/
template <typename _T>
class Stack
{
public:

/**
* @brief Constructor
*/
Stack()
: head(nullptr)
{
}

/**
* @brief Pop an element from the stack.
*
* @return _T* The pointer to the element popped from the stack
*/
_T* pop();

/**
* @brief Push an element to the stack.
*
* @param[in] p Pointer to the element to add to the stack.
*/
void push(_T* p);

/**
* @brief Get a pointer to the first element in the stack
*
* @return _T* The pointer to the first element
* @Note: SMP safety of this pointer is not guaranteed.
*/
_T* first();

private:
_T* head;
};

template <typename _T>
_T* Stack<_T>::first()
{
return head;
}

template <typename _T>
_T* Stack<_T>::pop()
{
auto original = head;
if (unlikely(nullptr == original))
{
return nullptr;
}
head = original->next;
return original;
}

template <typename _T>
void Stack<_T>::push(_T* p)
{
p->next = head;
head = p;
}

} // End NoLockFree namespace

} // End Util namespace

#endif // __UTIL_NOLOCKFREE_STACK_H

3 changes: 2 additions & 1 deletion src/lib/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
# Contributors Listed Below - COPYRIGHT 2010,2017
# Contributors Listed Below - COPYRIGHT 2010,2019
# [+] International Business Machines Corp.
#
#
Expand Down Expand Up @@ -50,6 +50,7 @@ OBJS += utilmisc.o

OBJS += tls.o
OBJS += errno.o
OBJS += tlsrt.o

ifdef HOSTBOOT_MEMORY_LEAKS
COMMONFLAGS += -DHOSTBOOT_MEMORY_LEAKS=1
Expand Down

0 comments on commit f547589

Please sign in to comment.