From d348a9a51d32cece842b7885d27a411436d7887b Mon Sep 17 00:00:00 2001
From: grischka <grischka>
Date: Tue, 12 Dec 2017 17:57:20 +0100
Subject: [PATCH] final update for 0.9.27

tccgen.c:
- fix ldouble asm hack
- fix a VLA problem on Win64 (also x86_64-gen.c)
- patch_type(): make sure that no symbol ever changes
  from global to static

tcc.c:
- tcc -vv: print libtcc1.a path also on win32

tccpe.c, tcctools.c:
- use unix LF mode to for .def output files (that is for
  creating reproducible output trees)

Makefile:
- suppress some warnings when makeinfo is missing
- call 'which install' only on win32

tests/Makefile:
- change PATH only on WINNT systems (i.e. not if cross-compiling
  on linux for win32)
- asm-c-connect.test: slim output and do diff

tccrun.c tccpe.c *-link.c:
- integrate former 'pe_relocate_rva()' into normal relocation
  This also fixes linkage of the unwind data on WIN64 for -run
  (reported by Janus Lynggaard Thorborg)

tccasm.c, tests/tcctest.c:
- fix dot (sym_index of -1 crashed in put_elf_reloc)
- massage .set a bit (see test)

other:
- #define SECTION_ABS removed
- ST_DATA Section *strtab_section: removed
- put_extern_sym2(): take int section number

Conflicts:
	tccelf.c
	tccpe.c

Conflicts:
	tccelf.c
---
 .gitignore              |  5 +++--
 Makefile                | 15 +++++++------
 arm-link.c              |  6 +++++
 arm64-link.c            |  6 +++++
 i386-link.c             |  3 +++
 tcc.c                   |  2 +-
 tcc.h                   | 19 +++++-----------
 tccasm.c                | 40 ++++++++++++++++++---------------
 tccelf.c                | 16 +++++++++-----
 tccgen.c                | 49 +++++++++++++++++++++--------------------
 tccpe.c                 | 31 ++++++--------------------
 tccrun.c                | 10 ++++++---
 tcctools.c              |  2 +-
 tests/Makefile          | 10 ++++-----
 tests/asm-c-connect-1.c | 17 ++++++++++----
 tests/asm-c-connect-2.c | 21 ++++++++++++++++--
 tests/tcctest.c         | 32 +++++++++++++++++++++++++++
 x86_64-gen.c            |  9 ++++++++
 x86_64-link.c           |  3 +++
 19 files changed, 187 insertions(+), 109 deletions(-)

diff --git a/.gitignore b/.gitignore
index 549c630a..c989b6be 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,16 +41,17 @@ win32/include/stddef.h
 win32/include/varargs.h
 win32/include/tcclib.h
 
-tests/test.out*
-tests/test*.out
 tests/tcctest[1234]
 tests/tcctest.gcc
+tests/*.out*
 tests/*.ref
 tests/*.txt
 tests/*.gcc
 tests/*-cc*
 tests/*-tcc*
 tests/libtcc_test
+tests/asm-c-connect
+tests/asm-c-connect-sep
 tests/vla_test
 tests/hello
 tests/tests2/fred.txt
diff --git a/Makefile b/Makefile
index 88881499..3ae466fd 100644
--- a/Makefile
+++ b/Makefile
@@ -239,14 +239,15 @@ FORCE:
 # --------------------------------------------------------------------------
 # documentation and man page
 tcc-doc.html: tcc-doc.texi
-	-makeinfo --no-split --html --number-sections -o $@ $<
+	makeinfo --no-split --html --number-sections -o $@ $< || true
 
 tcc.1: tcc-doc.texi
-	-$(TOPSRC)/texi2pod.pl $< tcc.pod
-	-pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod > $@
+	$(TOPSRC)/texi2pod.pl $< tcc.pod \
+	&& pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod >tmp.1 \
+	&& mv tmp.1 $@ || rm -f tmp.1
 
 tcc-doc.info: tcc-doc.texi
-	-makeinfo $<
+	makeinfo $< || true
 
 # --------------------------------------------------------------------------
 # install
@@ -304,7 +305,7 @@ ifneq "$(wildcard $(LIBTCC1_U))" ""
 endif
 
 # the msys-git shell works to configure && make except it does not have install
-ifeq ($(CONFIG_WIN32)-$(shell which install >/dev/null 2>&1 || echo no),yes-no)
+ifeq "$(and $(CONFIG_WIN32),$(shell which install >/dev/null 2>&1 || echo no))" "no"
 install-win : INSTALL = cp
 install-win : INSTALLBIN = cp
 endif
@@ -349,10 +350,10 @@ tests2.%:
 	$(MAKE) -C tests/tests2 $@
 
 clean:
-	rm -f $(PROGS) $(PROGS_CROSS) tcc_p$(EXESUF) tcc.pod
+	rm -f tcc$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF) tcc.pod
 	rm -f  *~ *.o *.a *.so* *.out *.log lib*.def *.exe *.dll a.out tags TAGS
-	@$(MAKE) -C tests $@
 	@$(MAKE) -C lib $@
+	@$(MAKE) -C tests $@
 
 distclean: clean
 	rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
diff --git a/arm-link.c b/arm-link.c
index aee35afe..92a24eba 100644
--- a/arm-link.c
+++ b/arm-link.c
@@ -382,6 +382,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
             /* Nothing to do.  Normally used to indicate a dependency
                on a certain symbol (like for exception handling under EABI).  */
             return;
+        case R_ARM_RELATIVE:
+#ifdef TCC_TARGET_PE
+            add32le(ptr, val - s1->pe_imagebase);
+#endif
+            /* do nothing */
+            return;
         default:
             fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
                 type, (unsigned)addr, ptr, (unsigned)val);
diff --git a/arm64-link.c b/arm64-link.c
index 73e503e6..59322c55 100644
--- a/arm64-link.c
+++ b/arm64-link.c
@@ -240,6 +240,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
 #endif
             write64le(ptr, val - rel->r_addend);
             return;
+        case R_AARCH64_RELATIVE:
+#ifdef TCC_TARGET_PE
+            add32le(ptr, val - s1->pe_imagebase);
+#endif
+            /* do nothing */
+            return;
         default:
             fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
                     type, (unsigned)addr, ptr, (unsigned)val);
diff --git a/i386-link.c b/i386-link.c
index b4466440..aea3c214 100644
--- a/i386-link.c
+++ b/i386-link.c
@@ -226,6 +226,9 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
             write16le(ptr, read16le(ptr) + val - addr);
             return;
         case R_386_RELATIVE:
+#ifdef TCC_TARGET_PE
+            add32le(ptr, val - s1->pe_imagebase);
+#endif
             /* do nothing */
             return;
         case R_386_COPY:
diff --git a/tcc.c b/tcc.c
index c347a06e..cd887d17 100644
--- a/tcc.c
+++ b/tcc.c
@@ -182,9 +182,9 @@ static void print_search_dirs(TCCState *s)
     /* print_dirs("programs", NULL, 0); */
     print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
     print_dirs("libraries", s->library_paths, s->nb_library_paths);
+    printf("libtcc1:\n  %s/"TCC_LIBTCC1"\n", s->tcc_lib_path);
 #ifndef TCC_TARGET_PE
     print_dirs("crt", s->crt_paths, s->nb_crt_paths);
-    printf("libtcc1:\n  %s/"TCC_LIBTCC1"\n", s->tcc_lib_path);
     printf("elfinterp:\n  %s\n",  DEFAULT_ELFINTERP(s));
 #endif
 }
diff --git a/tcc.h b/tcc.h
index 4fc273b8..cd679732 100644
--- a/tcc.h
+++ b/tcc.h
@@ -489,14 +489,6 @@ typedef struct Sym {
 } Sym;
 
 /* section definition */
-/* XXX: use directly ELF structure for parameters ? */
-/* special flag to indicate that the section should not be linked to
-   the other ones */
-#define SHF_PRIVATE 0x80000000
-
-/* special flag, too */
-#define SECTION_ABS ((void *)1)
-
 typedef struct Section {
     unsigned long data_offset; /* current data offset */
     unsigned char *data;       /* section data */
@@ -795,15 +787,13 @@ struct TCCState {
     struct sym_attr *sym_attrs;
     int nb_sym_attrs;
 
-    /* tiny assembler state */
-    ElfSym esym_dot;
-
 #ifdef TCC_TARGET_PE
     /* PE info */
     int pe_subsystem;
     unsigned pe_characteristics;
     unsigned pe_file_align;
     unsigned pe_stack_size;
+    addr_t pe_imagebase;
 # ifdef TCC_TARGET_X86_64
     Section *uw_pdata;
     int uw_sym;
@@ -1390,7 +1380,7 @@ ST_DATA Section *lbounds_section; /* contains local data bound description */
 ST_FUNC void tccelf_bounds_new(TCCState *s);
 #endif
 /* symbol sections */
-ST_DATA Section *symtab_section, *strtab_section;
+ST_DATA Section *symtab_section;
 /* debug sections */
 ST_DATA Section *stab_section, *stabstr_section;
 
@@ -1408,7 +1398,7 @@ ST_FUNC void section_reserve(Section *sec, unsigned long size);
 ST_FUNC Section *find_section(TCCState *s1, const char *name);
 ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags);
 
-ST_FUNC void put_extern_sym2(Sym *sym, Section *section, addr_t value, unsigned long size, int can_add_underscore);
+ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, addr_t value, unsigned long size, int can_add_underscore);
 ST_FUNC void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size);
 #if PTR_SIZE == 4
 ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
@@ -1551,6 +1541,9 @@ ST_FUNC void gen_bounded_ptr_deref(void);
 #ifdef TCC_TARGET_X86_64
 ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c);
 ST_FUNC void gen_opl(int op);
+#ifdef TCC_TARGET_PE
+ST_FUNC void gen_vla_result(int addr);
+#endif
 #endif
 
 /* ------------ arm-gen.c ------------ */
diff --git a/tccasm.c b/tccasm.c
index 355d158c..c035c8b4 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -32,7 +32,8 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
 }
 
 static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
-static Sym sym_dot;
+static Sym* asm_new_label(TCCState *s1, int label, int is_local);
+static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value);
 
 static Sym *asm_label_find(int v)
 {
@@ -73,6 +74,16 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
     return sym;
 }
 
+static Sym* asm_section_sym(TCCState *s1, Section *sec)
+{
+    char buf[100];
+    int label = tok_alloc(buf,
+        snprintf(buf, sizeof buf, "L.%s", sec->name)
+        )->tok;
+    Sym *sym = asm_label_find(label);
+    return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0);
+}
+
 /* We do not use the C expression parser to handle symbols. Maybe the
    C expression parser could be tweaked to do so. */
 
@@ -145,13 +156,9 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
         skip(')');
         break;
     case '.':
-        pe->v = 0;
-        pe->sym = &sym_dot;
-	pe->pcrel = 0;
-        sym_dot.type.t = VT_ASM | VT_STATIC;
-	sym_dot.c = -1;
-        tcc_state->esym_dot.st_shndx = cur_text_section->sh_num;
-        tcc_state->esym_dot.st_value = ind;
+        pe->v = ind;
+        pe->sym = asm_section_sym(s1, cur_text_section);
+        pe->pcrel = 0;
         next();
         break;
     default:
@@ -368,29 +375,26 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
 	/* A VT_EXTERN symbol, even if it has a section is considered
 	   overridable.  This is how we "define" .set targets.  Real
 	   definitions won't have VT_EXTERN set.  */
-        if (esym && esym->st_shndx != SHN_UNDEF && !(sym->type.t & VT_EXTERN)) {
+        if (esym && esym->st_shndx != SHN_UNDEF) {
             /* the label is already defined */
-            if (is_local != 1) {
-                tcc_error("assembler label '%s' already defined", 
-                      get_tok_str(label, NULL));
-            } else {
-                /* redefinition of local labels is possible */
+            if (IS_ASM_SYM(sym)
+                && (is_local == 1 || (sym->type.t & VT_EXTERN)))
                 goto new_label;
-            }
+            if (!(sym->type.t & VT_EXTERN))
+                tcc_error("assembler label '%s' already defined",
+                          get_tok_str(label, NULL));
         }
     } else {
     new_label:
         sym = asm_label_push(label);
     }
     if (!sym->c)
-      put_extern_sym2(sym, NULL, 0, 0, 0);
+      put_extern_sym2(sym, SHN_UNDEF, 0, 0, 0);
     esym = elfsym(sym);
     esym->st_shndx = sh_num;
     esym->st_value = value;
-
     if (is_local != 2)
         sym->type.t &= ~VT_EXTERN;
-
     return sym;
 }
 
diff --git a/tccelf.c b/tccelf.c
index 080c72bc..70d47e15 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -38,13 +38,18 @@ ST_DATA Section *bounds_section; /* contains global data bound description */
 ST_DATA Section *lbounds_section; /* contains local data bound description */
 #endif
 /* symbol sections */
-ST_DATA Section *symtab_section, *strtab_section;
+ST_DATA Section *symtab_section;
 /* debug sections */
 ST_DATA Section *stab_section, *stabstr_section;
 
 /* XXX: avoid static variable */
 static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
 
+/* special flag to indicate that the section should not be linked to the other ones */
+#define SHF_PRIVATE 0x80000000
+/* section is dynsymtab_section */
+#define SHF_DYNSYM 0x40000000
+
 /* ------------------------------------------------------------------------- */
 
 ST_FUNC void tccelf_new(TCCState *s)
@@ -63,11 +68,10 @@ ST_FUNC void tccelf_new(TCCState *s)
     symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
                                 ".strtab",
                                 ".hashtab", SHF_PRIVATE);
-    strtab_section = symtab_section->link;
     s->symtab = symtab_section;
 
     /* private symbol table for dynamic symbols */
-    s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
+    s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM,
                                       ".dynstrtab",
                                       ".dynhashtab", SHF_PRIVATE);
     get_sym_attr(s, 0, 1);
@@ -128,6 +132,8 @@ ST_FUNC void tccelf_delete(TCCState *s1)
     /* free loaded dlls array */
     dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
     tcc_free(s1->sym_attrs);
+
+    symtab_section = NULL; /* for tccrun.c:rt_printline() */
 }
 
 /* save section data state */
@@ -536,7 +542,7 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
                 goto do_patch;
             } else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) {
                 /* data symbol keeps precedence over common/bss */
-            } else if (s == tcc_state->dynsymtab_section) {
+            } else if (s->sh_flags & SHF_DYNSYM) {
                 /* we accept that two DLL define the same symbol */
 	    } else if (esym->st_other & ST_ASM_SET) {
 		/* If the existing symbol came from an asm .set
@@ -779,7 +785,7 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
     for_each_elem(symtab, 1, sym, ElfW(Sym)) {
         sh_num = sym->st_shndx;
         if (sh_num == SHN_UNDEF) {
-            name = (char *) strtab_section->data + sym->st_name;
+            name = (char *) s1->symtab->link->data + sym->st_name;
             /* Use ld.so to resolve symbol for us (for tcc -run) */
             if (do_resolve) {
 #if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
diff --git a/tccgen.c b/tccgen.c
index 7e10c18d..e0b744e2 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -285,10 +285,7 @@ ST_FUNC ElfSym *elfsym(Sym *s)
 {
   if (!s || !s->c)
     return NULL;
-  if (s->c == -1)
-    return &tcc_state->esym_dot;
-  else
-    return &((ElfSym *)symtab_section->data)[s->c];
+  return &((ElfSym *)symtab_section->data)[s->c];
 }
 
 /* apply storage attributes to Elf symbol */
@@ -338,11 +335,11 @@ ST_FUNC void update_storage(Sym *sym)
 /* update sym->c so that it points to an external symbol in section
    'section' with value 'value' */
 
-ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
+ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
                             addr_t value, unsigned long size,
                             int can_add_underscore)
 {
-    int sym_type, sym_bind, sh_num, info, other, t;
+    int sym_type, sym_bind, info, other, t;
     ElfSym *esym;
     const char *name;
     char buf1[256];
@@ -350,13 +347,6 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
     char buf[32];
 #endif
 
-    if (section == NULL)
-        sh_num = SHN_UNDEF;
-    else if (section == SECTION_ABS)
-        sh_num = SHN_ABS;
-    else
-        sh_num = section->sh_num;
-
     if (!sym->c) {
         name = get_tok_str(sym->v, NULL);
 #ifdef CONFIG_TCC_BCHECK
@@ -431,7 +421,8 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
 ST_FUNC void put_extern_sym(Sym *sym, Section *section,
                            addr_t value, unsigned long size)
 {
-    put_extern_sym2(sym, section, value, size, 1);
+    int sh_num = section ? section->sh_num : SHN_UNDEF;
+    put_extern_sym2(sym, sh_num, value, size, 1);
 }
 
 /* add a new relocation entry to symbol 'sym' in section 's' */
@@ -848,6 +839,7 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
     } else if (IS_ASM_SYM(s)) {
         s->type.t = type->t | (s->type.t & VT_EXTERN);
         s->type.ref = type->ref;
+        update_storage(s);
     }
     return s;
 }
@@ -862,9 +854,12 @@ static void patch_type(Sym *sym, CType *type)
     }
 
     if (IS_ASM_SYM(sym)) {
-        sym->type = *type;
+        /* stay static if both are static */
+        sym->type.t = type->t & (sym->type.t | ~VT_STATIC);
+        sym->type.ref = type->ref;
+    }
 
-    } else if (!is_compatible_types(&sym->type, type)) {
+    if (!is_compatible_types(&sym->type, type)) {
         tcc_error("incompatible types for redefinition of '%s'",
                   get_tok_str(sym->v, NULL));
 
@@ -876,10 +871,11 @@ static void patch_type(Sym *sym, CType *type)
                 get_tok_str(sym->v, NULL));
 
         if (0 == (type->t & VT_EXTERN)) {
-            /* put complete type */
-            sym->type = *type;
-            /* use static from prototype */
-            sym->type.t |= static_proto;
+            /* put complete type, use static from prototype */
+            sym->type.t = (type->t & ~VT_STATIC) | static_proto;
+            if (type->t & VT_INLINE)
+                sym->type.t = type->t;
+            sym->type.ref = type->ref;
         }
 
     } else {
@@ -6570,8 +6566,10 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
                     memcpy(ptr, &vtop->c.ld, 10);
 #ifdef __TINYC__
                 else if (sizeof (long double) == sizeof (double))
-                    __asm__("fldl %1\nfstpt %0\n" : "=m" (ptr) : "m" (vtop->c.ld));
+                    __asm__("fldl %1\nfstpt %0\n" : "=m" (*ptr) : "m" (vtop->c.ld));
 #endif
+                else if (vtop->c.ld == 0.0)
+                    ;
                 else
 #endif
                 if (sizeof(long double) == LDOUBLE_SIZE)
@@ -7019,6 +7017,11 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
 
         vla_runtime_type_size(type, &a);
         gen_vla_alloc(type, a);
+#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
+        /* on _WIN64, because of the function args scratch area, the
+           result of alloca differs from RSP and is returned in RAX.  */
+        gen_vla_result(addr), addr = (loc -= PTR_SIZE);
+#endif
         gen_vla_sp_save(addr);
         vla_sp_loc = addr;
         vlas_in_scope++;
@@ -7337,18 +7340,16 @@ found:
                         type.t |= VT_EXTERN;
                         sym = external_sym(v, &type, r, &ad);
                         if (ad.alias_target) {
-                            Section tsec;
                             ElfSym *esym;
                             Sym *alias_target;
                             alias_target = sym_find(ad.alias_target);
                             esym = elfsym(alias_target);
                             if (!esym)
                                 tcc_error("unsupported forward __alias__ attribute");
-                            tsec.sh_num = esym->st_shndx;
                             /* Local statics have a scope until now (for
                                warnings), remove it here.  */
                             sym->sym_scope = 0;
-                            put_extern_sym2(sym, &tsec, esym->st_value, esym->st_size, 0);
+                            put_extern_sym2(sym, esym->st_shndx, esym->st_value, esym->st_size, 0);
                         }
                     } else {
                         if (type.t & VT_STATIC)
diff --git a/tccpe.c b/tccpe.c
index 7e7150ce..a7266c9c 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -954,7 +954,7 @@ static void pe_build_exports(struct pe_info *pe)
     /* automatically write exports to <output-filename>.def */
     pstrcpy(buf, sizeof buf, pe->filename);
     strcpy(tcc_fileextension(buf), ".def");
-    op = fopen(buf, "w");
+    op = fopen(buf, "wb");
     if (NULL == op) {
         tcc_error_noabort("could not create '%s': %s", buf, strerror(errno));
     } else {
@@ -967,7 +967,7 @@ static void pe_build_exports(struct pe_info *pe)
     for (ord = 0; ord < sym_count; ++ord)
     {
         p = sorted[ord], sym_index = p->index, name = p->name;
-        /* insert actual address later in pe_relocate_rva */
+        /* insert actual address later in relocate_section() */
         put_elf_reloc(symtab_section, pe->thunk,
             func_o, R_XXX_RELATIVE, sym_index);
         *(DWORD*)(pe->thunk->data + name_o)
@@ -1181,26 +1181,6 @@ static int pe_assign_addresses (struct pe_info *pe)
     return 0;
 }
 
-/* ------------------------------------------------------------- */
-static void pe_relocate_rva (struct pe_info *pe, Section *s)
-{
-    Section *sr = s->reloc;
-    ElfW_Rel *rel, *rel_end;
-    rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
-    for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
-        if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) {
-            int sym_index = ELFW(R_SYM)(rel->r_info);
-            DWORD addr = s->sh_addr;
-            if (sym_index) {
-                ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
-                addr = sym->st_value;
-            }
-            // printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name);
-            *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
-        }
-    }
-}
-
 /*----------------------------------------------------------------------------*/
 
 static int pe_isafunc(int sym_index)
@@ -1830,7 +1810,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
 
     /* put relocations on it */
     for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress)
-        put_elf_reloc(symtab_section, pd, o,  R_X86_64_RELATIVE, s1->uw_sym);
+        put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym);
 }
 #endif
 /* ------------------------------------------------------------- */
@@ -1979,11 +1959,11 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
     else if (filename) {
         pe_assign_addresses(&pe);
         relocate_syms(s1, s1->symtab, 0);
+        s1->pe_imagebase = pe.imagebase;
         for (i = 1; i < s1->nb_sections; ++i) {
             Section *s = s1->sections[i];
             if (s->reloc) {
                 relocate_section(s1, s);
-                pe_relocate_rva(&pe, s);
             }
         }
         pe.start_addr = (DWORD)
@@ -1999,6 +1979,9 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
         pe.thunk = data_section;
         pe_build_imports(&pe);
         s1->runtime_main = pe.start_symbol;
+#ifdef TCC_TARGET_X86_64
+        s1->uw_pdata = find_section(s1, ".pdata");
+#endif
 #endif
     }
 
diff --git a/tccrun.c b/tccrun.c
index 20d72ce4..93601645 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -238,6 +238,10 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
     if (0 == mem)
         return offset + RUN_SECTION_ALIGNMENT;
 
+#ifdef TCC_TARGET_PE
+    s1->pe_imagebase = mem;
+#endif
+
     /* relocate each section */
     for(i = 1; i < s1->nb_sections; i++) {
         s = s1->sections[i];
@@ -306,11 +310,11 @@ static void *win64_add_function_table(TCCState *s1)
         RtlAddFunctionTable(
             (RUNTIME_FUNCTION*)p,
             s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
-            text_section->sh_addr
+            s1->pe_imagebase
             );
         s1->uw_pdata = NULL;
     }
-    return p;;
+    return p;
 }
 
 static void win64_del_function_table(void *p)
@@ -439,7 +443,7 @@ no_stabs:
                 if (wanted_pc >= sym->st_value &&
                     wanted_pc < sym->st_value + sym->st_size) {
                     pstrcpy(last_func_name, sizeof(last_func_name),
-                            (char *) strtab_section->data + sym->st_name);
+                            (char *) symtab_section->link->data + sym->st_name);
                     func_addr = sym->st_value;
                     goto found;
                 }
diff --git a/tcctools.c b/tcctools.c
index 53d88be6..1d4424ea 100644
--- a/tcctools.c
+++ b/tcctools.c
@@ -374,7 +374,7 @@ usage:
     if (v)
         printf("-> %s\n", file);
 
-    op = fopen(outfile, "w");
+    op = fopen(outfile, "wb");
     if (NULL == op) {
         fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
         goto the_end;
diff --git a/tests/Makefile b/tests/Makefile
index f06f39c3..5f6777d7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -51,9 +51,8 @@ ifndef CONFIG_cross
  TESTS := $(filter-out cross-%,$(TESTS))
 endif
 
-ifdef CONFIG_WIN32
- SEP = $(if $(findstring :\,$(PATH)),;,:)
- PATH := $(CURDIR)/$(TOP)$(SEP)$(PATH) # for libtcc_test to find libtcc.dll
+ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
+ PATH := $(CURDIR)/$(TOP)$(if $(findstring :\,$(PATH)),;,:)$(PATH)
 endif
 
 RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
@@ -243,8 +242,9 @@ asm-c-connect-sep$(EXESUF): asm-c-connect-1.o asm-c-connect-2.o
 
 asm-c-connect-test: asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
 	@echo ------------ $@ ------------
-	./asm-c-connect$(EXESUF)
-	./asm-c-connect-sep$(EXESUF)
+	./asm-c-connect$(EXESUF) > asm-c-connect.out1 && cat asm-c-connect.out1
+	./asm-c-connect-sep$(EXESUF) > asm-c-connect.out2 && cat asm-c-connect.out2
+	@diff -u asm-c-connect.out1 asm-c-connect.out2 && echo "ok"
 
 cross-test :
 	@echo ------------ $@ ------------
diff --git a/tests/asm-c-connect-1.c b/tests/asm-c-connect-1.c
index 1849b56d..8a28d781 100644
--- a/tests/asm-c-connect-1.c
+++ b/tests/asm-c-connect-1.c
@@ -8,7 +8,7 @@
 
 static int x1_c(void)
 {
-    printf("x1\n");
+    printf(" x1");
     return 1;
 }
 
@@ -16,21 +16,30 @@ asm(".text;"_"x1: call "_"x1_c; ret");
 
 void callx4(void);
 void callx5_again(void);
+
+void x6()
+{
+    printf(" x6-1");
+}
+
 int main(int argc, char *argv[])
 {
+    printf("*");
     asm("call "_"x1");
     asm("call "_"x2");
     asm("call "_"x3");
     callx4();
     asm("call "_"x5");
     callx5_again();
+    x6();
+    printf(" *\n");
     return 0;
 }
 
 static
 int x2(void)
 {
-    printf("x2\n");
+    printf(" x2");
     return 2;
 }
 
@@ -38,11 +47,11 @@ extern int x3(void);
 
 void x4(void)
 {
-    printf("x4\n");
+    printf(" x4");
 }
 
 void x5(void);
 void x5(void)
 {
-    printf("x5\n");
+    printf(" x5");
 }
diff --git a/tests/asm-c-connect-2.c b/tests/asm-c-connect-2.c
index 5dad26ce..3440b40b 100644
--- a/tests/asm-c-connect-2.c
+++ b/tests/asm-c-connect-2.c
@@ -1,19 +1,36 @@
 #include <stdio.h>
 
+#if defined _WIN32 && !defined __TINYC__
+# define _ "_"
+#else
+# define _
+#endif
+
 int x3(void)
 {
-    printf("x3\n");
+    printf(" x3");
     return 3;
 }
 
 /* That callx4 is defined globally (as if ".globl callx4")
    is a TCC extension.  GCC doesn't behave like this.  */
 void callx4(void);
-__asm__("callx4: call x4; ret");
+__asm__(_"callx4: call "_"x4; ret;"
+#ifndef __TINYC__
+    " .global "_"callx4"
+#endif
+);
 
 extern void x5(void);
+
 void callx5_again(void);
 void callx5_again(void)
 {
     x5();
+    asm("call "_"x6");
+}
+
+static void x6()
+{
+    printf(" x6-2");
 }
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 000523ec..57670bea 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -3370,6 +3370,37 @@ void test_asm_call(void)
 #endif
 }
 
+#if defined __x86_64__
+# define RX "(%rip)"
+#else
+# define RX
+#endif
+
+void asm_dot_test(void)
+{
+    int x;
+    for (x = 1;; ++x) {
+        int r = x;
+        switch (x) {
+        case 1:
+            asm(".text; lea S"RX",%eax; lea ."RX",%ecx; sub %ecx,%eax; S=.; jmp p0");
+        case 2:
+            asm(".text; jmp .+6; .int 123; mov .-4"RX",%eax; jmp p0");
+	case 3:
+            asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4");
+            asm(".text; mov X"RX",%eax; jmp p0");
+        case 4:
+            asm(".data; X=.; .int 789; Y=.; .int 999");
+            asm(".text; mov X"RX",%eax; X=Y; jmp p0");
+        case 0:
+	    asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break;
+	}
+        if (r == x)
+            break;
+        printf("asm_dot_test %d: %d\n", x, r);
+    }
+}
+
 void asm_test(void)
 {
     char buf[128];
@@ -3457,6 +3488,7 @@ void asm_test(void)
     trace_console(8, 8);
     test_asm_dead_code();
     test_asm_call();
+    asm_dot_test();
     return;
  label1:
     goto label2;
diff --git a/x86_64-gen.c b/x86_64-gen.c
index d7cb8953..e33a38a9 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -1034,6 +1034,7 @@ void gfunc_epilog(void)
     saved_ind = ind;
     ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
     /* align local size to word & save local variables */
+    func_scratch = (func_scratch + 15) & -16;
     v = (func_scratch + -loc + 15) & -16;
 
     if (v >= 4096) {
@@ -2222,6 +2223,14 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
     gen_modrm64(0x8b, TREG_RSP, VT_LOCAL, NULL, addr);
 }
 
+#ifdef TCC_TARGET_PE
+/* Save result of gen_vla_alloc onto the stack */
+ST_FUNC void gen_vla_result(int addr) {
+    /* mov %rax,addr(%rbp)*/
+    gen_modrm64(0x89, TREG_RAX, VT_LOCAL, NULL, addr);
+}
+#endif
+
 /* Subtract from the stack pointer, and push the resulting value onto the stack */
 ST_FUNC void gen_vla_alloc(CType *type, int align) {
 #ifdef TCC_TARGET_PE
diff --git a/x86_64-link.c b/x86_64-link.c
index c0c5e13b..a96144c7 100644
--- a/x86_64-link.c
+++ b/x86_64-link.c
@@ -287,6 +287,9 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
             add64le(ptr, val - s1->got->sh_addr);
             break;
         case R_X86_64_RELATIVE:
+#ifdef TCC_TARGET_PE
+            add32le(ptr, val - s1->pe_imagebase);
+#endif
             /* do nothing */
             break;
     }