From 71b0634168099422ff522cbcc9da5b5b111d7329 Mon Sep 17 00:00:00 2001
From: Michael Matz <matz@suse.de>
Date: Fri, 22 May 2020 04:28:02 +0200
Subject: [PATCH] Add find_c_sym and friends

for handling leading underscores when looking up symbols.
Necessary on MacOS, as there C symbols have a '_' prepended.
get_sym_addr (replacing get_elf_sym_addr) gets an argument to
specify if bare/raw/ELF symbols should be looked up or if decorated
C symbols should be looked up.  That reflects into tcc_get_symbol.
tcc_add_symbol is _not_ yet changed, but probably should be.
---
 tcc.h      |  3 ++-
 tccelf.c   | 32 ++++++++++++++++++++++++++------
 tccmacho.c |  2 +-
 tccrun.c   | 11 ++++++-----
 4 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/tcc.h b/tcc.h
index 4bb90132..c00c7a15 100644
--- a/tcc.h
+++ b/tcc.h
@@ -1535,7 +1535,8 @@ ST_FUNC void build_got_entries(TCCState *s1);
 ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
 ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset);
 
-ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err);
+ST_FUNC int find_c_sym(TCCState *, const char *name);
+ST_FUNC addr_t get_sym_addr(TCCState *s, const char *name, int err, int forc);
 ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
     void (*symbol_cb)(void *ctx, const char *name, const void *val));
 #if defined TCC_IS_NATIVE || defined TCC_TARGET_PE
diff --git a/tccelf.c b/tccelf.c
index 99effb6b..b7eeda6b 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -481,13 +481,33 @@ ST_FUNC int find_elf_sym(Section *s, const char *name)
     return 0;
 }
 
-/* return elf symbol value, signal error if 'err' is nonzero */
-ST_FUNC addr_t get_elf_sym_addr(TCCState *s1, const char *name, int err)
+ST_FUNC int find_c_sym(TCCState *s1, const char *name)
+{
+    int ret;
+    CString cstr;
+    if (s1->leading_underscore) {
+        cstr_new(&cstr);
+        cstr_ccat(&cstr, '_');
+        cstr_cat(&cstr, name, 0);
+        name = cstr.data;
+    }
+    ret = find_elf_sym(s1->symtab, name);
+    if (s1->leading_underscore)
+      cstr_free(&cstr);
+    return ret;
+}
+
+/* return elf symbol value, signal error if 'err' is nonzero, decorate
+   name if FORC */
+ST_FUNC addr_t get_sym_addr(TCCState *s1, const char *name, int err, int forc)
 {
     int sym_index;
     ElfW(Sym) *sym;
 
-    sym_index = find_elf_sym(s1->symtab, name);
+    if (forc)
+      sym_index = find_c_sym(s1, name);
+    else
+      sym_index = find_elf_sym(s1->symtab, name);
     sym = &((ElfW(Sym) *)s1->symtab->data)[sym_index];
     if (!sym_index || sym->st_shndx == SHN_UNDEF) {
         if (err)
@@ -524,7 +544,7 @@ ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
 /* return elf symbol value */
 LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name)
 {
-    return (void*)(uintptr_t)get_elf_sym_addr(s, name, 0);
+    return (void*)(uintptr_t)get_sym_addr(s, name, 0, 1);
 }
 
 /* list elf symbol names and values */
@@ -538,7 +558,7 @@ LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
 /* return elf symbol value or error */
 ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name)
 {
-    return (void*)(uintptr_t)get_elf_sym_addr(s, name, 1);
+    return (void*)(uintptr_t)get_sym_addr(s, name, 1, 1);
 }
 #endif
 
@@ -2177,7 +2197,7 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
     default:
     case TCC_OUTPUT_EXE:
         ehdr.e_type = ET_EXEC;
-        ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1);
+        ehdr.e_entry = get_sym_addr(s1, "_start", 1, 0);
         break;
     case TCC_OUTPUT_DLL:
         ehdr.e_type = ET_DYN;
diff --git a/tccmacho.c b/tccmacho.c
index 08b0f625..4507b762 100644
--- a/tccmacho.c
+++ b/tccmacho.c
@@ -818,7 +818,7 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename)
         Section *s;
         collect_sections(s1, &mo);
         relocate_syms(s1, s1->symtab, 0);
-        mo.ep.entryoff = get_elf_sym_addr(s1, "_main", 1) - mo.seg[1]->vmaddr;
+        mo.ep.entryoff = get_sym_addr(s1, "_main", 1, 0) - mo.seg[1]->vmaddr;
         if (s1->nb_errors)
           goto do_ret;
 
diff --git a/tccrun.c b/tccrun.c
index 92b0e647..944cd5a3 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -126,8 +126,8 @@ ST_FUNC void tcc_run_free(TCCState *s1)
 
 static void run_cdtors(TCCState *s1, const char *start, const char *end)
 {
-    void **a = tcc_get_symbol(s1, start);
-    void **b = tcc_get_symbol(s1, end);
+    void **a = (void **)get_sym_addr(s1, start, 0, 0);
+    void **b = (void **)get_sym_addr(s1, end, 0, 0);
     while (a != b)
         ((void(*)(void))*a++)();
 }
@@ -140,12 +140,12 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
     rt_context *rc = &g_rtctxt;
 #endif
 
-    s1->runtime_main = s1->nostdlib ? "_start" : s1->leading_underscore ? "_main" : "main";
-    if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
+    s1->runtime_main = s1->nostdlib ? "_start" : "main";
+    if ((s1->dflag & 16) && !find_c_sym(s1, s1->runtime_main))
         return 0;
 #ifdef CONFIG_TCC_BACKTRACE
     if (s1->do_debug)
-        tcc_add_symbol(s1, "exit", rt_exit);
+        tcc_add_symbol(s1, "_exit" + !s1->leading_underscore, rt_exit);
 #endif
     if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
         return -1;
@@ -182,6 +182,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
     errno = 0; /* clean errno value */
     fflush(stdout);
     fflush(stderr);
+    /* These aren't C symbols, so don't need leading underscore handling.  */
     run_cdtors(s1, "__init_array_start", "__init_array_end");
 #ifdef CONFIG_TCC_BACKTRACE
     if (!rc->do_jmp || !(ret = setjmp(rc->jmp_buf)))