better fix for bug #954173
[fw/sdcc] / as / mcs51 / lkrloc.c
index 37af57a29656e01ca8d95f0568c72a802a097f91..baa056496fe455baa649ef505d3340fa5d790c1e 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <alloc.h>
 #include "aslink.h"
 
 /*)Module      lkrloc.c
  *     perform the relocation calculations.
  *
  *     lkrloc.c contains the following functions:
- *             addr_t  adb_b()
- *             addr_t  adb_lo()
- *             addr_t  adb_hi()
- *             addr_t  adw_w()
- *             addr_t  adw_lo()
- *             addr_t  adw_hi()
+ *             Addr_T  adb_b()
+ *             Addr_T  adb_lo()
+ *             Addr_T  adb_hi()
+ *             Addr_T  adw_w()
+ *             Addr_T  adw_lo()
+ *             Addr_T  adw_hi()
  *             VOID    erpdmp()
  *             VOID    errdmp()
- *             addr_t  evword()
+ *             Addr_T  evword()
  *             VOID    prntval()
  *             VOID    rele()
  *             VOID    relerr()
  *
  */
 
+/* Global which holds the upper 16 bits of the last 32 bit area adress
+ * output. Useful only for iHex mode.
+ */
+int    lastExtendedAddress=-1;
+
+/* Static variable which holds the index of last processed area.
+ * Useful only for iHex mode.
+ */
+static int lastAreaIndex = -1;
+
 /*)Function    VOID    reloc(c)
  *
  *                     char c          process code
@@ -208,14 +217,14 @@ relt()
  *             int     lkerr           error flag
  *             int     mode            relocation mode
  *             adrr_t  paga            paging base area address
- *             addr_t  pags            paging symbol address
- *             addr_t  pc              relocated base address
- *             addr_t  r               PCR relocation value
- *             addr_t  reli            relocation initial value
- *             addr_t  relv            relocation final value
+ *             Addr_T  pags            paging symbol address
+ *             Addr_T  pc              relocated base address
+ *             Addr_T  r               PCR relocation value
+ *             Addr_T  reli            relocation initial value
+ *             Addr_T  relv            relocation final value
  *             int     rindex          symbol / area index
- *             addr_t  rtbase          base code address
- *             addr_t  rtofst          rtval[] index offset
+ *             Addr_T  rtbase          base code address
+ *             Addr_T  rtofst          rtval[] index offset
  *             int     rtp             index into T data
  *             sym     **s             pointer to array of symbol pointers
  *
@@ -225,11 +234,11 @@ relt()
  *             FILE    *stderr         standard error device
  *
  *     called functions:
- *             addr_t  adb_b()         lkrloc.c
- *             addr_t  adb_lo()        lkrloc.c
- *             addr_t  adb_hi()        lkrloc.c
- *             addr_t  adw_w()         lkrloc.c
- *             addr_t  evword()        lkrloc.c
+ *             Addr_T  adb_b()         lkrloc.c
+ *             Addr_T  adb_lo()        lkrloc.c
+ *             Addr_T  adb_hi()        lkrloc.c
+ *             Addr_T  adw_w()         lkrloc.c
+ *             Addr_T  evword()        lkrloc.c
  *             int     eval()          lkeval.c
  *             int     fprintf()       c_library
  *             VOID    ihx()           lkihx.c
@@ -250,9 +259,9 @@ VOID
 relr()
 {
        register int mode;
-       register addr_t reli, relv;
+       register Addr_T reli, relv;
        int aindex, rindex, rtp, error;
-       addr_t r, rtbase, rtofst, paga, pags, pc;
+       Addr_T r, rtbase, rtofst, paga, pags, pc;
        struct areax **a;
        struct sym **s;
 
@@ -291,12 +300,23 @@ relr()
         */
        pc = adw_w(a[aindex]->a_addr, 0);
 
+       #if 0
+       printf("area %d base address: 0x%x size: 0x%x rtbase: 0x%x\n", aindex, 
+               a[aindex]->a_addr, a[aindex]->a_size, rtbase);
+       #endif
        /*
         * Do remaining relocations
         */
        while (more()) {
                error = 0;
                mode = eval();
+               
+               if ((mode & R_ESCAPE_MASK) == R_ESCAPE_MASK)
+               {
+                   mode = ((mode & ~R_ESCAPE_MASK) << 8) | eval();
+                   /* printf("unescaping rmode\n"); */
+               }
+               
                rtp = eval();
                rindex = evword();
 
@@ -333,7 +353,7 @@ relr()
                /*
                 * R_PAG0 or R_PAG addressing
                 */
-               if (mode & (R_PAG0|R_PAG)) {
+               if (mode & (R_PAG0 | R_PAG)) {
                        paga  = sdp.s_area->a_addr;
                        pags  = sdp.s_addr;
                        reli -= paga + pags;
@@ -343,7 +363,38 @@ relr()
                 * R_BYTE or R_WORD operation
                 */
                if (mode & R_BYTE) {
-                       if (mode & R_BYT2) {
+                       if (mode & R_BYT3)
+                       {
+                               /* This is a three byte address, of which 
+                                * we will select one byte.
+                                */
+                               if (mode & R_HIB)
+                               {
+                                       /* printf("24 bit address selecting hi byte.\n"); */
+                                       relv = adb_24_hi(reli, rtp);
+                               }               
+                               else if (mode & R_MSB)
+                               {
+                                       /* Note that in 24 bit mode, R_MSB
+                                        * is really the middle byte, not
+                                        * the most significant byte.
+                                        *
+                                        * This is ugly and I can only apologize
+                                        * for any confusion.
+                                        */
+                                       /* printf("24 bit address selecting middle byte.\n"); */
+                                       relv = adb_24_mid(reli, rtp);                           
+                               }
+                               else
+                               {
+                                       /* printf("24 bit address selecting lo byte.\n"); */
+                                       relv = adb_24_lo(reli, rtp);                            
+                               }
+                       }
+                       else if (mode & R_BYT2) {
+                               /* This is a two byte address, of
+                                * which we will select one byte.
+                                */
                                if (mode & R_MSB) {
                                        relv = adb_hi(reli, rtp);
                                } else {
@@ -352,7 +403,7 @@ relr()
                        } else {
                                relv = adb_b(reli, rtp);
                        }
-               } else if (mode & R_J11) {
+               } else if (IS_R_J11(mode)) {
                        /* JLH: 11 bit jump destination for 8051.  Forms
                        /  two byte instruction with op-code bits
                        /  in the MIDDLE!
@@ -376,27 +427,41 @@ relr()
             rtval[rtp] = ((rtval[rtp] & 0x07)<<5) | rtval[rtp+2];
             rtflg[rtp+2] = 0;
                        rtofst += 1;
-               } else {
-                       /*
-                        * R_WORD with the R_BYT2 mode is flagged
-                        * as an 'r' error by the assembler,
-                        * but it is processed here anyway.
+               }
+               else if (IS_R_J19(mode)) {
+                       /* 19 bit jump destination for DS80C390.  Forms
+                       /  three byte instruction with op-code bits
+                       /  in the MIDDLE!
+                       /  rtp points at 4 byte locus: first three
+                       /  will get the instructiion. fourth one
+                       /  has raw op-code.
                         */
-#if 0
-                   /* JLH: R_WORD and R_BYT2 together is now subsumed by R_J11 */
-                       if (mode & R_BYT2) {
        
-                               if (mode & R_MSB) {
-                                       relv = adw_hi(reli, rtp);
-                               } else {
-                                       relv = adw_lo(reli, rtp);
+                       /* Calculate absolute destination
+                       /  relv must be on same 512K page as pc
+                       */
+                       relv = adw_24(reli, rtp);
+
+            if ((relv & ~0x7ffff) != ((pc + rtp - rtofst) & ~0x7ffff)) {
+                    error = 2;
                                }
-                       } else {
-                               relv = adw_w(reli, rtp);
+
+            /* Merge MSB (byte 0) with op-code, ignoring
+            /  top 5 bits of address.  Then hide the op-code
+            */
+            rtval[rtp] = ((rtval[rtp] & 0x07)<<5) | rtval[rtp+3];
+            rtflg[rtp+3] = 0;
+                       rtofst += 1;
+               }                
+               else if (IS_C24(mode))
+               {
+                       /* 24 bit address */
+                       relv = adw_24(reli, rtp);
                        }
-#else
+               else
+               {
+                       /* 16 bit address. */
                        relv = adw_w(reli, rtp);
-#endif
                }
 
                /*
@@ -419,7 +484,7 @@ relr()
                 */
                if (mode & R_PCR && mode & R_BYTE) {
                        r = relv & ~0x7F;
-                       if (r != (addr_t) ~0x7F && r != 0)
+                       if (r != (Addr_T) ~0x7F && r != 0)
                                error = 2; 
                }
 
@@ -449,6 +514,56 @@ relr()
 
        /* JLH: output only if data (beyond two byte address) */
        if ((oflag == 1) && (rtcnt > 2)) {
+               int extendedAddress = (a[aindex]->a_addr >> 16) & 0xffff;
+               
+               /* Boy, is this a hack: for ABS sections, the
+                * base address is stored as zero, and the T records
+                * indicate the offset from zero.
+                *
+                * Since T records can only indicate a 16 bit offset, this
+                * obviously creates a problem for ABS segments located
+                * above 64K (this is only meaningful in flat24 mode).
+                *
+                * However, the size of an ABS area is stored as
+                * base address + section size (I suspect this is a bug,
+                * but it's a handy one right now). So the upper 8 bits of
+                * the 24 bit address are stored in the size record.
+                * Thus we add it in.
+                *
+                * This is another reason why we can't have areas greater
+                * than 64K yet, even in flat24 mode.
+                */
+       //      extendedAddress += ((a[aindex]->a_size) >> 16 & 0xffff);
+       //      commented out by jr 
+               
+               if (lastAreaIndex != aindex) {
+                       lastAreaIndex = aindex;
+                       newArea();
+               }
+               
+               if (extendedAddress != lastExtendedAddress)
+               {
+               
+                   if (lastExtendedAddress!=-1) {
+                     printf("output extended linear address record 0x%x 0x%x\n",
+                            extendedAddress, lastExtendedAddress);
+                   }
+                   
+                   if (rflag)
+                   {
+                       ihxEntendedLinearAddress(extendedAddress);
+                   }
+                   else if (extendedAddress)
+                   {
+                       /* Not allowed to generate extended address records,
+                        * but one is called for here...
+                        */
+                       fprintf(stderr, 
+                               "warning: extended linear address encountered; "
+                               "you probably want the -r flag.\n");
+                   }
+                   lastExtendedAddress = extendedAddress;
+               }
                ihx(1);
        } else
        if ((oflag == 2) && (rtcnt > 2)) {
@@ -492,7 +607,7 @@ char *errmsg[] = {
  *             areax   **a             pointer to array of area pointers
  *             int     aindex          area index
  *             int     mode            relocation mode
- *             addr_t  relv    relocation value
+ *             Addr_T  relv    relocation value
  *             int     rindex          symbol / area index
  *             int     rtp                     index into T data
  *             sym     **s                     pointer to array of symbol pointers
@@ -504,8 +619,8 @@ char *errmsg[] = {
  *             FILE *stderr    standard error device
  *
  *     called functions:
- *             addr_t adw_w()  lkrloc.c
- *             addr_t evword() lkrloc.c
+ *             Addr_T adw_w()  lkrloc.c
+ *             Addr_T evword() lkrloc.c
  *             int     eval()          lkeval.c
  *             int     fprintf()       c_library
  *             int     more()          lklex.c
@@ -523,7 +638,7 @@ relp()
 {
        register int aindex, rindex;
        int mode, rtp;
-       addr_t relv;
+       Addr_T relv;
        struct areax **a;
        struct sym **s;
 
@@ -632,13 +747,13 @@ rele()
        }
 }
 
-/*)Function    addr_t          evword()
+/*)Function    Addr_T          evword()
  *
  *     The function evword() combines two byte values
  *     into a single word value.
  *
  *     local variable:
- *             addr_t  v               temporary evaluation variable
+ *             Addr_T  v               temporary evaluation variable
  *
  *     global variables:
  *             hilo                    byte ordering parameter
@@ -652,10 +767,10 @@ rele()
  *
  */
 
-addr_t
+Addr_T
 evword()
 {
-       register addr_t v;
+       register Addr_T v;
 
        if (hilo) {
                v =  (eval() << 8);
@@ -667,7 +782,7 @@ evword()
        return(v);
 }
 
-/*)Function    addr_t          adb_b(v, i)
+/*)Function    Addr_T          adb_b(v, i)
  *
  *             int     v               value to add to byte
  *             int     i               rtval[] index
@@ -690,15 +805,15 @@ evword()
  *
  */
 
-addr_t
+Addr_T
 adb_b(v, i)
-register addr_t v;
+register Addr_T v;
 register int i;
 {
        return(rtval[i] += v);
 }
 
-/*)Function    addr_t          adb_lo(v, i)
+/*)Function    Addr_T          adb_lo(v, i)
  *
  *             int     v               value to add to byte
  *             int     i               rtval[] index
@@ -709,7 +824,7 @@ register int i;
  *     The MSB rtflg[] is cleared.
  *
  *     local variable:
- *             addr_t  j               temporary evaluation variable
+ *             Addr_T  j               temporary evaluation variable
  *
  *     global variables:
  *             hilo                    byte ordering parameter
@@ -725,12 +840,12 @@ register int i;
  *
  */
 
-addr_t
+Addr_T
 adb_lo(v, i)
-addr_t v;
+Addr_T v;
 int    i;
 {
-       register addr_t j;
+       register Addr_T j;
 
        j = adw_w(v, i);
        /*
@@ -744,7 +859,7 @@ int i;
        return (j);
 }
 
-/*)Function    addr_t          adb_hi(v, i)
+/*)Function    Addr_T          adb_hi(v, i)
  *
  *             int     v               value to add to byte
  *             int     i               rtval[] index
@@ -755,7 +870,7 @@ int i;
  *     The LSB rtflg[] is cleared.
  *
  *     local variable:
- *             addr_t  j               temporary evaluation variable
+ *             Addr_T  j               temporary evaluation variable
  *
  *     global variables:
  *             hilo                    byte ordering parameter
@@ -771,12 +886,12 @@ int       i;
  *
  */
 
-addr_t
+Addr_T
 adb_hi(v, i)
-addr_t v;
+Addr_T v;
 int    i;
 {
-       register addr_t j;
+       register Addr_T j;
 
        j = adw_w(v, i);
        /*
@@ -790,7 +905,144 @@ int       i;
        return (j);
 }
 
-/*)Function    addr_t          adw_w(v, i)
+/*)Function    Addr_T          adb_24_hi(v, i)
+ *
+ *             int     v               value to add to byte
+ *             int     i               rtval[] index
+ *
+ *     The function adb_24_hi() adds the value of v to the
+ *     24 bit value contained in rtval[i] - rtval[i+2].
+ *     The new value of rtval[i] / rtval[i+1] is returned.
+ *     The LSB & middle byte rtflg[] is cleared.
+ *
+ *     local variable:
+ *             Addr_T  j               temporary evaluation variable
+ *
+ *     global variables:
+ *             hilo                    byte ordering parameter
+ *
+ *     called functions:
+ *             none
+ *
+ *     side effects:
+ *             The value of rtval[] is changed.
+ *             The rtflg[] value corresponding to the
+ *             LSB & middle byte of the word value is cleared to
+ *             reflect the fact that the MSB is the selected byte.
+ *
+ */
+
+Addr_T
+adb_24_hi(Addr_T v, int i)
+{
+       register Addr_T j;
+
+       j = adw_24(v, i);
+
+       /* Remove the lower two bytes. */
+       if (hilo)
+       {
+           rtflg[i+2] = 0;
+       }
+       else
+       {
+           rtflg[i] = 0;
+       }
+       rtflg[i+1] = 0;
+
+       return (j);
+}
+
+/*)Function    Addr_T          adb_24_mid(v, i)
+ *
+ *             int     v               value to add to byte
+ *             int     i               rtval[] index
+ *
+ *     The function adb_24_mid() adds the value of v to the
+ *     24 bit value contained in rtval[i] - rtval[i+2].
+ *     The new value of rtval[i] / rtval[i+1] is returned.
+ *     The LSB & MSB byte rtflg[] is cleared.
+ *
+ *     local variable:
+ *             Addr_T  j               temporary evaluation variable
+ *
+ *     global variables:
+ *             hilo                    byte ordering parameter
+ *
+ *     called functions:
+ *             none
+ *
+ *     side effects:
+ *             The value of rtval[] is changed.
+ *             The rtflg[] value corresponding to the
+ *             LSB & MSB of the 24 bit value is cleared to reflect
+ *             the fact that the middle byte is the selected byte.
+ *
+ */
+
+Addr_T
+adb_24_mid(Addr_T v, int i)
+{
+       register Addr_T j;
+
+       j = adw_24(v, i);
+
+       /* remove the MSB & LSB. */
+       rtflg[i+2] = 0;
+       rtflg[i] = 0;
+
+       return (j);
+}
+
+/*)Function    Addr_T          adb_24_lo(v, i)
+ *
+ *             int     v               value to add to byte
+ *             int     i               rtval[] index
+ *
+ *     The function adb_24_lo() adds the value of v to the
+ *     24 bit value contained in rtval[i] - rtval[i+2].
+ *     The new value of rtval[i] / rtval[i+1] is returned.
+ *     The MSB & middle byte rtflg[] is cleared.
+ *
+ *     local variable:
+ *             Addr_T  j               temporary evaluation variable
+ *
+ *     global variables:
+ *             hilo                    byte ordering parameter
+ *
+ *     called functions:
+ *             none
+ *
+ *     side effects:
+ *             The value of rtval[] is changed.
+ *             The rtflg[] value corresponding to the
+ *             MSB & middle byte  of the word value is cleared to
+ *             reflect the fact that the LSB is the selected byte.
+ *
+ */
+
+Addr_T
+adb_24_lo(Addr_T v, int i)
+{
+       register Addr_T j;
+
+       j = adw_24(v, i);
+
+       /* Remove the upper two bytes. */
+       if (hilo)
+       {
+           rtflg[i] = 0;
+       }
+       else
+       {
+           rtflg[i+2] = 0;
+       }
+       rtflg[i+1] = 0;
+
+       return (j);
+}
+
+/*)Function    Addr_T          adw_w(v, i)
  *
  *             int     v               value to add to word
  *             int     i               rtval[] index
@@ -800,7 +1052,7 @@ int        i;
  *     The new value of rtval[i] / rtval[i+1] is returned.
  *
  *     local variable:
- *             addr_t  j               temporary evaluation variable
+ *             Addr_T  j               temporary evaluation variable
  *
  *     global variables:
  *             hilo                    byte ordering parameter
@@ -813,12 +1065,12 @@ int      i;
  *
  */
 
-addr_t
+Addr_T
 adw_w(v, i)
-register addr_t v;
+register Addr_T v;
 register int i;
 {
-       register addr_t j;
+       register Addr_T j;
 
        if (hilo) {
                j = v + (rtval[i] << 8) + (rtval[i+1] & 0xff);
@@ -832,7 +1084,52 @@ register int i;
        return(j);
 }
 
-/*)Function    addr_t          adw_lo(v, i)
+/*)Function    Addr_T          adw_24(v, i)
+ *
+ *             int     v               value to add to word
+ *             int     i               rtval[] index
+ *
+ *     The function adw_w() adds the value of v to the
+ *     24 bit value contained in rtval[i] - rtval[i+2].
+ *     The new value of rtval[i] - rtval[i+2] is returned.
+ *
+ *     local variable:
+ *             Addr_T  j               temporary evaluation variable
+ *
+ *     global variables:
+ *             hilo                    byte ordering parameter
+ *
+ *     called functions:
+ *             none
+ *
+ *     side effects:
+ *             The word value of rtval[] is changed.
+ *
+ */
+Addr_T
+adw_24(Addr_T v, int i)
+{
+       register Addr_T j;
+
+       if (hilo) {
+               j = v + ((rtval[i] & 0xff) << 16) 
+                     + ((rtval[i+1] & 0xff) << 8)
+                     + (rtval[i+2] & 0xff);
+               rtval[i] = (j >> 16) & 0xff;
+               rtval[i+1] = (j >> 8) & 0xff;
+               rtval[i+2] = j & 0xff;
+       } else {
+               j = v + (rtval[i] & 0xff) 
+                     + ((rtval[i+1] & 0xff) << 8)
+                     + ((rtval[i+2] & 0xff) << 16);
+               rtval[i] = j & 0xff;
+               rtval[i+1] = (j >> 8) & 0xff;
+               rtval[i+2] = (j >> 16) & 0xff;
+       }
+       return(j);
+}
+
+/*)Function    Addr_T          adw_lo(v, i)
  *
  *             int     v               value to add to byte
  *             int     i               rtval[] index
@@ -843,7 +1140,7 @@ register int i;
  *     The MSB rtval[] is zeroed.
  *
  *     local variable:
- *             addr_t  j               temporary evaluation variable
+ *             Addr_T  j               temporary evaluation variable
  *
  *     global variables:
  *             hilo                    byte ordering parameter
@@ -858,12 +1155,12 @@ register int i;
  *
  */
 
-addr_t
+Addr_T
 adw_lo(v, i)
-addr_t v;
+Addr_T v;
 int    i;
 {
-       register addr_t j;
+       register Addr_T j;
 
        j = adw_w(v, i);
        /*
@@ -877,7 +1174,7 @@ int        i;
        return (j);
 }
 
-/*)Function    addr_t          adw_hi(v, i)
+/*)Function    Addr_T          adw_hi(v, i)
  *
  *             int     v               value to add to byte
  *             int     i               rtval[] index
@@ -889,7 +1186,7 @@ int        i;
  *     The MSB rtval[] is zeroed.
  *
  *     local variable:
- *             addr_t  j               temporary evaluation variable
+ *             Addr_T  j               temporary evaluation variable
  *
  *     global variables:
  *             hilo                    byte ordering parameter
@@ -904,12 +1201,12 @@ int      i;
  *
  */
 
-addr_t
+Addr_T
 adw_hi(v, i)
-addr_t v;
+Addr_T v;
 int    i;
 {
-       register addr_t j;
+       register Addr_T j;
 
        j = adw_w(v, i);
        /*
@@ -1054,7 +1351,7 @@ char *str;
 /*)Function    VOID prntval(fptr, v)
  *
  *             FILE    *fptr   output file handle
- *             addr_t  v               value to output
+ *             Addr_T  v               value to output
  *
  *     The function prntval() outputs the value v, in the
  *     currently selected radix, to the device specified
@@ -1077,7 +1374,7 @@ char *str;
 VOID
 prntval(fptr, v)
 FILE *fptr;
-addr_t v;
+Addr_T v;
 {
        if (xflag == 0) {
                fprintf(fptr, "%04X\n", v);