Fix "times" relocation handling.

Previously a line such as "times 4 mov rax, [rel foobar]" would result
in incorrect relocations being generated.

Patch by: bird-yasm@anduin.net

[#211 state:resolved]
diff --git a/libyasm/bc-align.c b/libyasm/bc-align.c
index fd7c8f5..763140d 100644
--- a/libyasm/bc-align.c
+++ b/libyasm/bc-align.c
@@ -58,7 +58,8 @@
 static int bc_align_expand(yasm_bytecode *bc, int span, long old_val,
                            long new_val, /*@out@*/ long *neg_thres,
                            /*@out@*/ long *pos_thres);
-static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                            unsigned char *bufstart, void *d,
                             yasm_output_value_func output_value,
                             /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -164,7 +165,8 @@
 }
 
 static int
-bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                 unsigned char *bufstart, void *d,
                  yasm_output_value_func output_value,
                  /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
diff --git a/libyasm/bc-data.c b/libyasm/bc-data.c
index 1a62d20..7fe4091 100644
--- a/libyasm/bc-data.c
+++ b/libyasm/bc-data.c
@@ -70,7 +70,8 @@
 static int bc_data_item_size(yasm_bytecode *bc);
 static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
                             void *add_span_data);
-static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                           unsigned char *bufstart, void *d,
                            yasm_output_value_func output_value,
                            /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -203,13 +204,13 @@
 }
 
 static int
-bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                unsigned char *bufstart, void *d,
                 yasm_output_value_func output_value,
                 /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     bytecode_data *bc_data = (bytecode_data *)bc->contents;
     yasm_dataval *dv;
-    unsigned char *bufp_orig = *bufp;
     yasm_intnum *intn;
     unsigned int val_len;
     unsigned long multiple, i;
@@ -224,7 +225,7 @@
                 val_len = dv->data.val.size/8;
                 for (i=0; i<multiple; i++) {
                     if (output_value(&dv->data.val, *bufp, val_len,
-                                     (unsigned long)(*bufp-bufp_orig), bc, 1,
+                                     (unsigned long)(*bufp-bufstart), bc, 1,
                                      d))
                         return 1;
                     *bufp += val_len;
diff --git a/libyasm/bc-incbin.c b/libyasm/bc-incbin.c
index f2bee74..2314601 100644
--- a/libyasm/bc-incbin.c
+++ b/libyasm/bc-incbin.c
@@ -58,7 +58,8 @@
 static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
                               void *add_span_data);
-static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                             unsigned char *bufstart, void *d,
                              yasm_output_value_func output_value,
                              /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -195,7 +196,8 @@
 }
 
 static int
-bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                  unsigned char *bufstart, void *d,
                   yasm_output_value_func output_value,
                   /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
diff --git a/libyasm/bc-org.c b/libyasm/bc-org.c
index b6f101c..cb2d82b 100644
--- a/libyasm/bc-org.c
+++ b/libyasm/bc-org.c
@@ -52,7 +52,8 @@
 static int bc_org_expand(yasm_bytecode *bc, int span, long old_val,
                          long new_val, /*@out@*/ long *neg_thres,
                          /*@out@*/ long *pos_thres);
-static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                          unsigned char *bufstart, void *d,
                           yasm_output_value_func output_value,
                           /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -120,7 +121,8 @@
 }
 
 static int
-bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+               unsigned char *bufstart, void *d,
                yasm_output_value_func output_value,
                /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
diff --git a/libyasm/bc-reserve.c b/libyasm/bc-reserve.c
index 5cfd38a..09196fa 100644
--- a/libyasm/bc-reserve.c
+++ b/libyasm/bc-reserve.c
@@ -50,7 +50,8 @@
 static int bc_reserve_calc_len(yasm_bytecode *bc,
                                yasm_bc_add_span_func add_span,
                                void *add_span_data);
-static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                              unsigned char *bufstart, void *d,
                               yasm_output_value_func output_value,
                               /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -114,7 +115,8 @@
 }
 
 static int
-bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                   unsigned char *bufstart, void *d,
                    yasm_output_value_func output_value,
                    /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
diff --git a/libyasm/bytecode.c b/libyasm/bytecode.c
index 851085c..50a4fa0 100644
--- a/libyasm/bytecode.c
+++ b/libyasm/bytecode.c
@@ -73,7 +73,8 @@
 }
 
 int
-yasm_bc_tobytes_common(yasm_bytecode *bc, unsigned char **bufp, void *d,
+yasm_bc_tobytes_common(yasm_bytecode *bc, unsigned char **buf,
+                       unsigned char *bufstart, void *d,
                        yasm_output_value_func output_value,
                        /*@null@*/ yasm_output_reloc_func output_reloc)
 {
@@ -305,6 +306,7 @@
     /*@sets *buf@*/
 {
     /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL;
+    unsigned char *bufstart;
     unsigned char *origbuf, *destbuf;
     long i;
     int error = 0;
@@ -329,6 +331,7 @@
         destbuf = mybuf;
     } else
         destbuf = buf;
+    bufstart = destbuf;
 
     *bufsize = bc->len*bc->mult_int;
 
@@ -336,7 +339,7 @@
         yasm_internal_error(N_("got empty bytecode in bc_tobytes"));
     else for (i=0; i<bc->mult_int; i++) {
         origbuf = destbuf;
-        error = bc->callback->tobytes(bc, &destbuf, d, output_value,
+        error = bc->callback->tobytes(bc, &destbuf, bufstart, d, output_value,
                                       output_reloc);
 
         if (!error && ((unsigned long)(destbuf - origbuf) != bc->len))
diff --git a/libyasm/bytecode.h b/libyasm/bytecode.h
index 0753ccf..2b66427 100644
--- a/libyasm/bytecode.h
+++ b/libyasm/bytecode.h
@@ -147,6 +147,8 @@
      *                      passed-in buf matches the bytecode length
      *                      (it's okay not to do this if an error
      *                      indication is returned)
+     * \param bufstart      For calculating the correct offset parameter for
+     *                      the \a output_value calls: *bufp - bufstart.
      * \param d             data to pass to each call to
      *                      output_value/output_reloc
      * \param output_value  function to call to convert values into their byte
@@ -158,7 +160,8 @@
      *       preferable if calling this function twice would result in the
      *       same output.
      */
-    int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp,
+                    unsigned char *bufstart, void *d,
                     yasm_output_value_func output_value,
                     /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -277,7 +280,7 @@
  */
 YASM_LIB_DECL
 int yasm_bc_tobytes_common
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
diff --git a/modules/arch/lc3b/lc3bbc.c b/modules/arch/lc3b/lc3bbc.c
index a5d0192..51029cd 100644
--- a/modules/arch/lc3b/lc3bbc.c
+++ b/modules/arch/lc3b/lc3bbc.c
@@ -44,6 +44,7 @@
                                long new_val, /*@out@*/ long *neg_thres,
                                /*@out@*/ long *pos_thres);
 static int lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                                unsigned char *bufstart,
                                 void *d, yasm_output_value_func output_value,
                                 /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -165,12 +166,14 @@
 }
 
 static int
-lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                     unsigned char *bufstart, void *d,
                      yasm_output_value_func output_value,
                      /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     lc3b_insn *insn = (lc3b_insn *)bc->contents;
     /*@only@*/ yasm_intnum *delta;
+    unsigned long buf_off = (unsigned long)(*bufp - bufstart);
 
     /* Output opcode */
     YASM_SAVE_16_L(*bufp, insn->opcode);
@@ -181,29 +184,29 @@
             break;
         case LC3B_IMM_4:
             insn->imm.size = 4;
-            if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
+            if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d))
                 return 1;
             break;
         case LC3B_IMM_5:
             insn->imm.size = 5;
             insn->imm.sign = 1;
-            if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
+            if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d))
                 return 1;
             break;
         case LC3B_IMM_6_WORD:
             insn->imm.size = 6;
-            if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
+            if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d))
                 return 1;
             break;
         case LC3B_IMM_6_BYTE:
             insn->imm.size = 6;
             insn->imm.sign = 1;
-            if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
+            if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d))
                 return 1;
             break;
         case LC3B_IMM_8:
             insn->imm.size = 8;
-            if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
+            if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d))
                 return 1;
             break;
         case LC3B_IMM_9_PC:
@@ -220,12 +223,12 @@
 
             insn->imm.size = 9;
             insn->imm.sign = 1;
-            if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
+            if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d))
                 return 1;
             break;
         case LC3B_IMM_9:
             insn->imm.size = 9;
-            if (output_value(&insn->imm, *bufp, 2, 0, bc, 1, d))
+            if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d))
                 return 1;
             break;
         default:
diff --git a/modules/arch/x86/x86bc.c b/modules/arch/x86/x86bc.c
index c329f2e..49df4f8 100644
--- a/modules/arch/x86/x86bc.c
+++ b/modules/arch/x86/x86bc.c
@@ -44,6 +44,7 @@
                               long new_val, /*@out@*/ long *neg_thres,
                               /*@out@*/ long *pos_thres);
 static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                               unsigned char *bufstart,
                                void *d, yasm_output_value_func output_value,
                                /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -56,6 +57,7 @@
                              long new_val, /*@out@*/ long *neg_thres,
                              /*@out@*/ long *pos_thres);
 static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                              unsigned char *bufstart,
                               void *d, yasm_output_value_func output_value,
                               /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -66,7 +68,7 @@
                                   yasm_bc_add_span_func add_span,
                                   void *add_span_data);
 static int x86_bc_jmpfar_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -800,14 +802,14 @@
 }
 
 static int
-x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                    unsigned char *bufstart, void *d,
                     yasm_output_value_func output_value,
                     /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     x86_insn *insn = (x86_insn *)bc->contents;
     /*@null@*/ x86_effaddr *x86_ea = (x86_effaddr *)insn->x86_ea;
     yasm_value *imm = insn->imm;
-    unsigned char *bufp_orig = *bufp;
 
     /* Prefixes */
     x86_common_tobytes(&insn->common, bufp,
@@ -874,7 +876,7 @@
                                          yasm_expr_int(delta), bc->line);
             }
             if (output_value(&x86_ea->ea.disp, *bufp, disp_len,
-                             (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+                             (unsigned long)(*bufp-bufstart), bc, 1, d))
                 return 1;
             *bufp += disp_len;
         }
@@ -892,7 +894,7 @@
             imm_len = 1;
         } else
             imm_len = imm->size/8;
-        if (output_value(imm, *bufp, imm_len, (unsigned long)(*bufp-bufp_orig),
+        if (output_value(imm, *bufp, imm_len, (unsigned long)(*bufp-bufstart),
                          bc, 1, d))
             return 1;
         *bufp += imm_len;
@@ -902,14 +904,14 @@
 }
 
 static int
-x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                   unsigned char *bufstart, void *d,
                    yasm_output_value_func output_value,
                    /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     x86_jmp *jmp = (x86_jmp *)bc->contents;
     unsigned char opersize;
     unsigned int i;
-    unsigned char *bufp_orig = *bufp;
     /*@only@*/ yasm_intnum *delta;
 
     /* Prefixes */
@@ -944,7 +946,7 @@
             jmp->target.size = 8;
             jmp->target.sign = 1;
             if (output_value(&jmp->target, *bufp, 1,
-                             (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+                             (unsigned long)(*bufp-bufstart), bc, 1, d))
                 return 1;
             *bufp += 1;
             break;
@@ -976,7 +978,7 @@
             jmp->target.size = i*8;
             jmp->target.sign = 1;
             if (output_value(&jmp->target, *bufp, i,
-                             (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+                             (unsigned long)(*bufp-bufstart), bc, 1, d))
                 return 1;
             *bufp += i;
             break;
@@ -989,13 +991,13 @@
 }
 
 static int
-x86_bc_jmpfar_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+x86_bc_jmpfar_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                      unsigned char *bufstart, void *d,
                       yasm_output_value_func output_value,
                       /*@unused@*/ yasm_output_reloc_func output_reloc)
 {
     x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
     unsigned int i;
-    unsigned char *bufp_orig = *bufp;
     unsigned char opersize;
 
     x86_common_tobytes(&jmpfar->common, bufp, 0);
@@ -1009,12 +1011,12 @@
     i = (opersize == 16) ? 2 : 4;
     jmpfar->offset.size = i*8;
     if (output_value(&jmpfar->offset, *bufp, i,
-                     (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+                     (unsigned long)(*bufp-bufstart), bc, 1, d))
         return 1;
     *bufp += i;
     jmpfar->segment.size = 16;
     if (output_value(&jmpfar->segment, *bufp, 2,
-                     (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+                     (unsigned long)(*bufp-bufstart), bc, 1, d))
         return 1;
     *bufp += 2;
 
diff --git a/modules/dbgfmts/codeview/cv-symline.c b/modules/dbgfmts/codeview/cv-symline.c
index ca31271..8a79729 100644
--- a/modules/dbgfmts/codeview/cv-symline.c
+++ b/modules/dbgfmts/codeview/cv-symline.c
@@ -163,7 +163,7 @@
 static int cv8_symhead_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int cv8_symhead_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -173,7 +173,7 @@
 static int cv8_fileinfo_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int cv8_fileinfo_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -183,7 +183,7 @@
 static int cv8_lineinfo_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int cv8_lineinfo_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -192,7 +192,7 @@
 static int cv_sym_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int cv_sym_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -727,7 +727,8 @@
 }
 
 static int
-cv8_symhead_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+cv8_symhead_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                       unsigned char *bufstart, void *d,
                        yasm_output_value_func output_value,
                        yasm_output_reloc_func output_reloc)
 {
@@ -800,7 +801,8 @@
 }
 
 static int
-cv8_fileinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+cv8_fileinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                        unsigned char *bufstart, void *d,
                         yasm_output_value_func output_value,
                         yasm_output_reloc_func output_reloc)
 {
@@ -867,7 +869,8 @@
 }
 
 static int
-cv8_lineinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+cv8_lineinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                        unsigned char *bufstart, void *d,
                         yasm_output_value_func output_value,
                         yasm_output_reloc_func output_reloc)
 {
@@ -879,7 +882,8 @@
     cv8_lineset *ls;
 
     /* start offset and section */
-    cv_out_sym(li->sectsym, 0, bc, &buf, d, output_value);
+    cv_out_sym(li->sectsym, (unsigned long)(buf - bufstart), bc, &buf,
+               d, output_value);
 
     /* Two bytes of pad/alignment */
     YASM_WRITE_8(buf, 0);
@@ -1022,7 +1026,8 @@
 }
 
 static int
-cv_sym_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+cv_sym_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                  unsigned char *bufstart, void *d,
                   yasm_output_value_func output_value,
                   yasm_output_reloc_func output_reloc)
 {
@@ -1064,7 +1069,7 @@
                 break;
             case 'Y':
                 cv_out_sym((yasm_symrec *)cvs->args[arg++].p,
-                           (unsigned long)(buf-(*bufp)), bc, &buf, d,
+                           (unsigned long)(buf-bufstart), bc, &buf, d,
                            output_value);
                 break;
             case 'T':
diff --git a/modules/dbgfmts/codeview/cv-type.c b/modules/dbgfmts/codeview/cv-type.c
index 862bea4..7951625 100644
--- a/modules/dbgfmts/codeview/cv-type.c
+++ b/modules/dbgfmts/codeview/cv-type.c
@@ -483,7 +483,7 @@
 static int cv_type_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int cv_type_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -732,7 +732,8 @@
 }
 
 static int
-cv_type_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+cv_type_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                   unsigned char *bufstart, void *d,
                    yasm_output_value_func output_value,
                    yasm_output_reloc_func output_reloc)
 {
diff --git a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c
index d015f5c..85c5e50 100644
--- a/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c
+++ b/modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c
@@ -46,7 +46,7 @@
 static int dwarf2_head_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int dwarf2_head_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -248,7 +248,8 @@
 }
 
 static int
-dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                       unsigned char *bufstart, void *d,
                        yasm_output_value_func output_value,
                        yasm_output_reloc_func output_reloc)
 {
@@ -288,7 +289,7 @@
                                 yasm_section_bcs_first(head->debug_ptr)),
             dbgfmt_dwarf2->sizeof_offset*8);
         output_value(&value, buf, dbgfmt_dwarf2->sizeof_offset,
-                     (unsigned long)(buf-*bufp), bc, 0, d);
+                     (unsigned long)(buf-bufstart), bc, 0, d);
         buf += dbgfmt_dwarf2->sizeof_offset;
     }
 
diff --git a/modules/dbgfmts/dwarf2/dwarf2-info.c b/modules/dbgfmts/dwarf2/dwarf2-info.c
index eebce33..7265750 100644
--- a/modules/dbgfmts/dwarf2/dwarf2-info.c
+++ b/modules/dbgfmts/dwarf2/dwarf2-info.c
@@ -197,7 +197,7 @@
 static int dwarf2_abbrev_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int dwarf2_abbrev_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -397,7 +397,8 @@
 }
 
 static int
-dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                         unsigned char *bufstart, void *d,
                          yasm_output_value_func output_value,
                          yasm_output_reloc_func output_reloc)
 {
diff --git a/modules/dbgfmts/dwarf2/dwarf2-line.c b/modules/dbgfmts/dwarf2/dwarf2-line.c
index e961eb3..d2f55e5 100644
--- a/modules/dbgfmts/dwarf2/dwarf2-line.c
+++ b/modules/dbgfmts/dwarf2/dwarf2-line.c
@@ -132,7 +132,7 @@
 static int dwarf2_spp_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int dwarf2_spp_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -142,7 +142,7 @@
 static int dwarf2_line_op_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int dwarf2_line_op_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -777,7 +777,8 @@
 }
 
 static int
-dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                      unsigned char *bufstart, void *d,
                       yasm_output_value_func output_value,
                       yasm_output_reloc_func output_reloc)
 {
@@ -861,7 +862,8 @@
 }
 
 static int
-dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                          unsigned char *bufstart, void *d,
                           yasm_output_value_func output_value,
                           yasm_output_reloc_func output_reloc)
 {
@@ -879,7 +881,7 @@
             yasm_value_init_sym(&value, line_op->ext_operand,
                                 line_op->ext_operandsize*8);
             output_value(&value, buf, line_op->ext_operandsize,
-                         (unsigned long)(buf-*bufp), bc, 0, d);
+                         (unsigned long)(buf-bufstart), bc, 0, d);
             buf += line_op->ext_operandsize;
         }
         if (line_op->ext_operand_int) {
diff --git a/modules/dbgfmts/stabs/stabs-dbgfmt.c b/modules/dbgfmts/stabs/stabs-dbgfmt.c
index 247639e..a4ad289 100644
--- a/modules/dbgfmts/stabs/stabs-dbgfmt.c
+++ b/modules/dbgfmts/stabs/stabs-dbgfmt.c
@@ -119,7 +119,7 @@
 static int stabs_bc_str_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int stabs_bc_str_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -129,7 +129,7 @@
 static int stabs_bc_stab_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int stabs_bc_stab_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -405,7 +405,8 @@
 }
 
 static int
-stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                      unsigned char *bufstart, void *d,
                       yasm_output_value_func output_value,
                       yasm_output_reloc_func output_reloc)
 {
@@ -439,7 +440,8 @@
 }
 
 static int
-stabs_bc_str_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+stabs_bc_str_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                     unsigned char *bufstart, void *d,
                      yasm_output_value_func output_value,
                      yasm_output_reloc_func output_reloc)
 {
diff --git a/modules/objfmts/coff/coff-objfmt.c b/modules/objfmts/coff/coff-objfmt.c
index 0f94156..0591884 100644
--- a/modules/objfmts/coff/coff-objfmt.c
+++ b/modules/objfmts/coff/coff-objfmt.c
@@ -230,7 +230,7 @@
 static int win32_sxdata_bc_calc_len
     (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
 static int win32_sxdata_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -1761,7 +1761,8 @@
 }
 
 static int
-win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                        unsigned char *bufstart, void *d,
                         yasm_output_value_func output_value,
                         yasm_output_reloc_func output_reloc)
 {
diff --git a/modules/objfmts/coff/win64-except.c b/modules/objfmts/coff/win64-except.c
index 5596eac..32ef919 100644
--- a/modules/objfmts/coff/win64-except.c
+++ b/modules/objfmts/coff/win64-except.c
@@ -48,7 +48,7 @@
                                   long new_val, /*@out@*/ long *neg_thres,
                                   /*@out@*/ long *pos_thres);
 static int win64_uwinfo_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -63,7 +63,7 @@
                                   long new_val, /*@out@*/ long *neg_thres,
                                   /*@out@*/ long *pos_thres);
 static int win64_uwcode_bc_tobytes
-    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
      yasm_output_value_func output_value,
      /*@null@*/ yasm_output_reloc_func output_reloc);
 
@@ -279,7 +279,8 @@
 }
 
 static int
-win64_uwinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+win64_uwinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                        unsigned char *bufstart, void *d,
                         yasm_output_value_func output_value,
                         yasm_output_reloc_func output_reloc)
 {
@@ -295,12 +296,12 @@
         YASM_WRITE_8(buf, 1);
 
     /* Size of prolog */
-    output_value(&info->prolog_size, buf, 1, (unsigned long)(buf-*bufp),
+    output_value(&info->prolog_size, buf, 1, (unsigned long)(buf-*bufstart),
                  bc, 1, d);
     buf += 1;
 
     /* Count of codes */
-    output_value(&info->codes_count, buf, 1, (unsigned long)(buf-*bufp),
+    output_value(&info->codes_count, buf, 1, (unsigned long)(buf-bufstart),
                  bc, 1, d);
     buf += 1;
 
@@ -459,7 +460,8 @@
 }
 
 static int
-win64_uwcode_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+win64_uwcode_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
+                        unsigned char *bufstart, void *d,
                         yasm_output_value_func output_value,
                         yasm_output_reloc_func output_reloc)
 {
@@ -476,7 +478,7 @@
         yasm_expr_create(YASM_EXPR_SUB, yasm_expr_sym(code->loc),
                          yasm_expr_sym(code->proc), bc->line),
         8);
-    output_value(&val, buf, 1, (unsigned long)(buf-*bufp), bc, 1, d);
+    output_value(&val, buf, 1, (unsigned long)(buf-bufstart), bc, 1, d);
     buf += 1;
     yasm_value_delete(&val);
 
diff --git a/modules/objfmts/elf/tests/amd64/Makefile.inc b/modules/objfmts/elf/tests/amd64/Makefile.inc
index 58b6156..7d10d9c 100644
--- a/modules/objfmts/elf/tests/amd64/Makefile.inc
+++ b/modules/objfmts/elf/tests/amd64/Makefile.inc
@@ -9,3 +9,5 @@
 EXTRA_DIST += modules/objfmts/elf/tests/amd64/elfso64.hex
 EXTRA_DIST += modules/objfmts/elf/tests/amd64/gotpcrel.asm
 EXTRA_DIST += modules/objfmts/elf/tests/amd64/gotpcrel.hex
+EXTRA_DIST += modules/objfmts/elf/tests/amd64/multiplefixup.asm
+EXTRA_DIST += modules/objfmts/elf/tests/amd64/multiplefixup.hex
diff --git a/modules/objfmts/elf/tests/amd64/multiplefixup.asm b/modules/objfmts/elf/tests/amd64/multiplefixup.asm
new file mode 100644
index 0000000..ec253cb
--- /dev/null
+++ b/modules/objfmts/elf/tests/amd64/multiplefixup.asm
@@ -0,0 +1,8 @@
+[section .data]
+foobar:
+	dq	42
+[section .text]
+foo:
+	times 4 mov rax, [rel foobar]
+	times 4 mov rax, [foobar]
+	times 4 jmp foo
diff --git a/modules/objfmts/elf/tests/amd64/multiplefixup.hex b/modules/objfmts/elf/tests/amd64/multiplefixup.hex
new file mode 100644
index 0000000..16565ff
--- /dev/null
+++ b/modules/objfmts/elf/tests/amd64/multiplefixup.hex
@@ -0,0 +1,992 @@
+7f 
+45 
+4c 
+46 
+02 
+01 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+3e 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+20 
+02 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+40 
+00 
+00 
+00 
+00 
+00 
+40 
+00 
+07 
+00 
+01 
+00 
+48 
+8b 
+05 
+00 
+00 
+00 
+00 
+48 
+8b 
+05 
+00 
+00 
+00 
+00 
+48 
+8b 
+05 
+00 
+00 
+00 
+00 
+48 
+8b 
+05 
+00 
+00 
+00 
+00 
+48 
+8b 
+04 
+25 
+00 
+00 
+00 
+00 
+48 
+8b 
+04 
+25 
+00 
+00 
+00 
+00 
+48 
+8b 
+04 
+25 
+00 
+00 
+00 
+00 
+48 
+8b 
+04 
+25 
+00 
+00 
+00 
+00 
+eb 
+c2 
+eb 
+c0 
+eb 
+be 
+eb 
+bc 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+fc 
+ff 
+ff 
+ff 
+ff 
+ff 
+ff 
+ff 
+0a 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+fc 
+ff 
+ff 
+ff 
+ff 
+ff 
+ff 
+ff 
+11 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+fc 
+ff 
+ff 
+ff 
+ff 
+ff 
+ff 
+ff 
+18 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+fc 
+ff 
+ff 
+ff 
+ff 
+ff 
+ff 
+ff 
+20 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0a 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+28 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0a 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+30 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0a 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+38 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0a 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+2a 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+2e 
+74 
+65 
+78 
+74 
+00 
+2e 
+64 
+61 
+74 
+61 
+00 
+2e 
+72 
+65 
+6c 
+61 
+2e 
+74 
+65 
+78 
+74 
+00 
+2e 
+73 
+74 
+72 
+74 
+61 
+62 
+00 
+2e 
+73 
+79 
+6d 
+74 
+61 
+62 
+00 
+2e 
+73 
+68 
+73 
+74 
+72 
+74 
+61 
+62 
+00 
+00 
+00 
+00 
+2d 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+04 
+00 
+f1 
+ff 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+06 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+06 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+28 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+4c 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+32 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+18 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+80 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+20 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+84 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+90 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+06 
+00 
+00 
+00 
+08 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+18 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+06 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+40 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+44 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+10 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0d 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+84 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+c0 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+08 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+18 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+07 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+44 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+08 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00