diff --git a/i386-asm.c b/i386-asm.c
index e134d804..57bd7e6d 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -487,7 +487,7 @@ ST_FUNC void gen_expr32(ExprValue *pe)
     if (pe->pcrel)
         /* If PC-relative, always set VT_SYM, even without symbol,
 	   so as to force a relocation to be emitted.  */
-	gen_addrpc32(VT_SYM, pe->sym, pe->v);
+	gen_addrpc32(VT_SYM, pe->sym, pe->v + (ind + 4));
     else
 	gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
 }
diff --git a/tccasm.c b/tccasm.c
index 19425976..c5ee4173 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -323,6 +323,8 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
 		ElfSym *esym1, *esym2;
 		esym1 = elfsym(pe->sym);
 		esym2 = elfsym(e2.sym);
+		if (!esym2)
+		    goto cannot_relocate;
 		if (esym1 && esym1->st_shndx == esym2->st_shndx
 		    && esym1->st_shndx != SHN_UNDEF) {
 		    /* we also accept defined symbols in the same section */
@@ -331,7 +333,7 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
 		} else if (esym2->st_shndx == cur_text_section->sh_num) {
 		    /* When subtracting a defined symbol in current section
 		       this actually makes the value PC-relative.  */
-		    pe->v -= esym2->st_value - ind - 4;
+		    pe->v += 0 - esym2->st_value;
 		    pe->pcrel = 1;
 		    e2.sym = NULL;
 		} else {
diff --git a/tccgen.c b/tccgen.c
index f6aaf6c1..791c5c6d 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -1204,6 +1204,8 @@ static void patch_type(Sym *sym, CType *type)
         /* stay static if both are static */
         sym->type.t = type->t & (sym->type.t | ~VT_STATIC);
         sym->type.ref = type->ref;
+        if ((type->t & VT_BTYPE) != VT_FUNC && !(type->t & VT_ARRAY))
+            sym->r |= VT_LVAL;
     }
 
     if (!is_compatible_types(&sym->type, type)) {
diff --git a/tests/tcctest.c b/tests/tcctest.c
index b49cd450..eb47a0eb 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -3758,6 +3758,16 @@ void asm_dot_test(void)
 #endif
 }
 
+void asm_pcrel_test(void)
+{
+    unsigned o1, o2;
+    /* subtract text-section label from forward or other-section label */
+    asm("1: mov $2f-1b,%%eax; mov %%eax,%0" : "=m"(o1));
+    /* verify ... */
+    asm("2: mov $2b,%%eax; sub $1b,%%eax; mov %%eax,%0" : "=m"(o2));
+    printf("%s : %x\n", __FUNCTION__, o1 - o2); /* should be zero */
+}
+
 void asm_test(void)
 {
     char buf[128];
@@ -3849,6 +3859,7 @@ void asm_test(void)
     test_asm_dead_code();
     test_asm_call();
     asm_dot_test();
+    asm_pcrel_test();
     return;
  label1:
     goto label2;