summaryrefslogtreecommitdiffstats
path: root/linkers/rtems-syms.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linkers/rtems-syms.cpp')
-rw-r--r--linkers/rtems-syms.cpp206
1 files changed, 152 insertions, 54 deletions
diff --git a/linkers/rtems-syms.cpp b/linkers/rtems-syms.cpp
index bfe2a48..9dd845f 100644
--- a/linkers/rtems-syms.cpp
+++ b/linkers/rtems-syms.cpp
@@ -53,19 +53,31 @@
/**
* Header text.
*/
-static const char* c_header[] =
+static const char* const c_header[] =
{
"/*",
" * RTEMS Global Symbol Table",
" * Automatically generated. Do not edit..",
" */",
"",
+ "#include <stddef.h>",
+ "#include <stdint.h>",
+ "",
+ "extern void* rtems_rtl_tls_get_base (void);",
+ "",
"extern const unsigned char rtems__rtl_base_globals[];",
"extern const unsigned int rtems__rtl_base_globals_size[];",
"",
- "void rtems_rtl_base_sym_global_add (const unsigned char* , unsigned int );",
+ "typedef size_t (*rtems_rtl_tls_offset_func)(void);",
+ "typedef struct rtems_rtl_tls_offset {",
+ " size_t index;",
+ " rtems_rtl_tls_offset_func offset;",
+ "} rtems_rtl_tls_offset;",
"",
- "asm(\".section \\\".rodata\\\"\");",
+ "void rtems_rtl_base_sym_global_add (const unsigned char* , unsigned int,",
+ " rtems_rtl_tls_offset*, size_t );",
+ "",
+ "asm(\".pushsection \\\".rodata\\\"\");",
"",
"asm(\" .align 4\");",
"asm(\" .local rtems__rtl_base_globals\");",
@@ -78,35 +90,61 @@ static const char* c_header[] =
0
};
-static const char* c_trailer[] =
+static const char* const c_sym_table_end[] =
{
"asm(\" .byte 0\");",
"asm(\" .ascii \\\"\\xde\\xad\\xbe\\xef\\\"\");",
-#if BROKEN_ON_SOME_ASSEMBLERS
- "asm(\" .type rtems__rtl_base_globals, #object\");",
- "asm(\" .size rtems__rtl_base_globals, . - rtems__rtl_base_globals\");",
-#endif
"",
+ 0
+};
+
+static const char* const c_tls_call_table_start[] =
+{
+ "rtems_rtl_tls_offset rtems_rtl_tls_offsets[] = {",
+ 0
+};
+
+static const char* const c_tls_call_table_end[] =
+{
+ "};",
+ "#define RTEMS_RTL_TLS_OFFSETS_NUM " \
+ "(sizeof(rtems_rtl_tls_offsets) / (sizeof(rtems_rtl_tls_offsets[0])))",
+ "",
+ 0
+};
+
+static const char* const c_trailer[] =
+{
"/*",
" * Symbol table size.",
" */",
"asm(\" .align 4\");",
"asm(\" .local rtems__rtl_base_globals_size\");",
-#if BROKEN_ON_SOME_ASSEMBLERS
- "asm(\" .type rtems__rtl_base_globals_size, #object\");",
- "asm(\" .size rtems__rtl_base_globals_size, 4\");",
-#endif
"asm(\"rtems__rtl_base_globals_size:\");",
"asm(\" .long rtems__rtl_base_globals_size - rtems__rtl_base_globals\");",
+ "asm(\" .popsection\");",
"",
0
};
-static const char* c_rtl_call_body[] =
+static const char* const c_rtl_call_body_embeded[] =
{
"{",
" rtems_rtl_base_sym_global_add (&rtems__rtl_base_globals[0],",
- " rtems__rtl_base_globals_size[0]);",
+ " rtems__rtl_base_globals_size[0],",
+ " &rtems_rtl_tls_offsets[0],",
+ " RTEMS_RTL_TLS_OFFSETS_NUM);",
+ "}",
+ 0
+};
+
+static const char* const c_rtl_call_body[] =
+{
+ "{",
+ " rtems_rtl_base_sym_global_add (&rtems__rtl_base_globals[0],",
+ " rtems__rtl_base_globals_size[0],",
+ " NULL,",
+ " 0);",
"}",
0
};
@@ -115,7 +153,7 @@ static const char* c_rtl_call_body[] =
* Paint the data to the temporary file.
*/
static void
-temporary_file_paint (rld::process::tempfile& t, const char* lines[])
+temporary_file_paint (rld::process::tempfile& t, const char* const lines[])
{
for (int l = 0; lines[l]; ++l)
t.write_line (lines[l]);
@@ -140,7 +178,7 @@ c_embedded_trailer (rld::process::tempfile& c)
{
c.write_line ("void rtems_rtl_base_global_syms_init(void);");
c.write_line ("void rtems_rtl_base_global_syms_init(void)");
- temporary_file_paint (c, c_rtl_call_body);
+ temporary_file_paint (c, c_rtl_call_body_embeded);
}
/**
@@ -214,16 +252,27 @@ symbol_filter::filter (const rld::symbols::symtab& symbols,
struct output_sym
{
+ enum struct output_mode {
+ symbol,
+ tls_func,
+ tls_call_table
+ };
rld::process::tempfile& c;
const bool embed;
const bool weak;
-
- output_sym(rld::process::tempfile& c,
- bool embed,
- bool weak)
- : c (c),
- embed (embed),
- weak (weak) {
+ const output_mode mode;
+ size_t& index;
+
+ output_sym(rld::process::tempfile& c_,
+ bool embed_,
+ bool weak_,
+ output_mode mode_,
+ size_t& index_)
+ : c (c_),
+ embed (embed_),
+ weak (weak_),
+ mode (mode_),
+ index (index_) {
}
void operator ()(const rld::symbols::symtab::value_type& value);
@@ -240,34 +289,66 @@ output_sym::operator ()(const rld::symbols::symtab::value_type& value)
if (weak && sym.value () == 0)
return;
- c.write_line ("asm(\" .asciz \\\"" + sym.name () + "\\\"\");");
-
- if (embed)
- {
- c.write_line ("#if __riscv_xlen == 64");
- c.write_line ("asm(\" .quad " + sym.name () + "\");");
- c.write_line ("#else");
- c.write_line ("asm(\" .long " + sym.name () + "\");");
- c.write_line ("#endif");
- }
- else
- {
- std::stringstream oss;
- oss << std::hex << std::setfill ('0') << std::setw (8) << sym.value ();
- c.write_line ("#if __riscv_xlen == 64");
- c.write_line ("asm(\" .quad 0x" + oss.str () + "\");");
- c.write_line ("#else");
- c.write_line ("asm(\" .long 0x" + oss.str () + "\");");
- c.write_line ("#endif");
+ switch (mode) {
+ case output_mode::symbol:
+ default:
+ /*
+ * Set TLS value to 0. It is filled in at run time by the call
+ * table.
+ */
+ c.write_line ("asm(\" .asciz \\\"" + sym.name () + "\\\"\");");
+ {
+ std::string val;
+ if (sym.type () == STT_TLS) {
+ val = "0";
+ } else {
+ if (embed) {
+ val = sym.name ();
+ } else {
+ std::stringstream oss;
+ oss << std::hex << std::showbase << std::internal <<
+ std::setfill ('0') << std::setw (10) << sym.value ();
+ val = oss.str ();
+ }
+ }
+ c.write_line ("#if __SIZEOF_POINTER__ == 8");
+ c.write_line ("asm(\" .quad " + val + "\");");
+ c.write_line ("#else");
+ c.write_line ("asm(\" .long " + val + "\");");
+ c.write_line ("#endif");
+ }
+ break;
+ case output_mode::tls_func:
+ if (sym.type () == STT_TLS) {
+ c.write_line ("#define RTEMS_TLS_INDEX_" + sym.name () + " " + std::to_string(index));
+ c.write_line ("static size_t rtems_rtl_tls_" + sym.name () + "(void) {");
+ c.write_line (" extern __thread char " + sym.name () + "[];");
+ c.write_line (" size_t tls_base = (size_t) rtems_rtl_tls_get_base ();");
+ c.write_line (" size_t tls_addr = (size_t) " + sym.name () + ";");
+ c.write_line (" return tls_addr - tls_base;");
+ c.write_line ("}");
+ c.write_line ("");
+ }
+ break;
+ case output_mode::tls_call_table:
+ if (sym.type () == STT_TLS) {
+ c.write_line (" { RTEMS_TLS_INDEX_" + sym.name () +
+ ", rtems_rtl_tls_" + sym.name () + " },");
+ }
+ break;
}
+ ++index;
}
-
static void
generate_c (rld::process::tempfile& c,
rld::symbols::symtab& symbols,
bool embed)
{
+ if (rld::verbose ())
+ std::cout << "symbol C file: " << c.name () << std::endl;
+
+ c.open (true);
temporary_file_paint (c, c_header);
/*
@@ -276,9 +357,28 @@ generate_c (rld::process::tempfile& c,
* longer weak and should be consider a global symbol. You cannot link a
* global symbol with the same in a dynamically loaded module.
*/
+ size_t index = 0;
std::for_each (symbols.begin (),
symbols.end (),
- output_sym (c, embed, false));
+ output_sym (c, embed, false,
+ output_sym::output_mode::symbol, index));
+
+ temporary_file_paint (c, c_sym_table_end);
+
+ if (embed) {
+ index = 0;
+ std::for_each (symbols.begin (),
+ symbols.end (),
+ output_sym (c, embed, false,
+ output_sym::output_mode::tls_func, index));
+ temporary_file_paint (c, c_tls_call_table_start);
+ index = 0;
+ std::for_each (symbols.begin (),
+ symbols.end (),
+ output_sym (c, embed, false,
+ output_sym::output_mode::tls_call_table, index));
+ temporary_file_paint (c, c_tls_call_table_end);
+ }
temporary_file_paint (c, c_trailer);
@@ -294,11 +394,6 @@ generate_symmap (rld::process::tempfile& c,
rld::symbols::symtab& symbols,
bool embed)
{
- c.open (true);
-
- if (rld::verbose ())
- std::cout << "symbol C file: " << c.name () << std::endl;
-
generate_c (c, symbols, embed);
if (rld::verbose ())
@@ -526,8 +621,8 @@ main (int argc, char* argv[])
throw rld::error ("no kernel file", "options");
if (argc != 1)
throw rld::error ("only one kernel file", "options");
- if (output.empty () && map.empty ())
- throw rld::error ("no output or map", "options");
+ if (output.empty () && symc.empty() && map.empty ())
+ throw rld::error ("no output, symbol C file, or map", "options");
kernel_name = *argv;
@@ -587,7 +682,7 @@ main (int argc, char* argv[])
/*
* Create an output file if asked too.
*/
- if (!output.empty ())
+ if (!output.empty () || !symc.empty())
{
rld::process::tempfile c (".c");
@@ -598,9 +693,12 @@ main (int argc, char* argv[])
}
/*
- * Generate and compile the symbol map.
+ * Generate and if requested compile the symbol map.
*/
- generate_symmap (c, output, filter_symbols, embed);
+ if (output.empty())
+ generate_c (c, filter_symbols, embed);
+ else
+ generate_symmap (c, output, filter_symbols, embed);
}
kernel.close ();