blob: 3244d0602092f62236ffcfd7a645e3eb444099b5 [file] [log] [blame]
From dd799e32d1e14eaebba8c6c6a91615f24695f8aa Mon Sep 17 00:00:00 2001
From: Adrien Destugues <pulkomandy@pulkomandy.tk>
Date: Fri, 22 Jan 2016 21:01:19 +0100
Subject: Kevin Thacker's patch for runtime relocation support.
This patch is used to build the Contiki operating system for Z80
machines.
This version is modified for SDCC 4.2, the addresses are now internally
stored on 24 bits instead of 16 bits (to help support banked code), and
the code in the patch was adjusted for that.
diff --git a/sdas/linksrc/Makefile.in b/sdas/linksrc/Makefile.in
index 43e16f5..e37b167 100644
--- a/sdas/linksrc/Makefile.in
+++ b/sdas/linksrc/Makefile.in
@@ -47,7 +47,7 @@ ASXXLIBSRC = strcmpi.c
SRC = lk_readnl.c lkaomf51.c lkar.c lkarea.c lkdata.c lkelf.c lkeval.c \
lkhead.c lklex.c lklib.c lklibr.c lklist.c lkmain.c lkmem.c \
lknoice.c lkout.c lkrel.c lkrloc.c lkrloc3.c lks19.c lksdcclib.c \
- lksym.c sdld.c lksdcdb.c lkbank.c
+ lksym.c sdld.c lksdcdb.c lkbank.c lkrrel.c
LKSOURCES = $(SRC) $(ASXXLIBSRC:%.c=$(ASXXLIB)/%.c)
diff --git a/sdas/linksrc/aslink.h b/sdas/linksrc/aslink.h
index 94c2b7b..f898a19 100644
--- a/sdas/linksrc/aslink.h
+++ b/sdas/linksrc/aslink.h
@@ -1033,6 +1033,8 @@ extern int yflag; /* -y, enable SDCC Debug output
*/
#endif
+extern int hflag; /* Generate relocatable executable
+ */
extern int pflag; /* print linker command file flag
*/
extern int uflag; /* Listing relocation flag
diff --git a/sdas/linksrc/lkdata.c b/sdas/linksrc/lkdata.c
index 169e8c1..8686631 100644
--- a/sdas/linksrc/lkdata.c
+++ b/sdas/linksrc/lkdata.c
@@ -66,6 +66,9 @@ int oflag; /* Output file type flag
int objflg; /* Linked file/library object output flag
*/
+int hflag; /* Generate relocatable executable
+ */
+
#if NOICE
int jflag; /* NoICE output flag
*/
diff --git a/sdas/linksrc/lkmain.c b/sdas/linksrc/lkmain.c
index daf5515..d690d46 100644
--- a/sdas/linksrc/lkmain.c
+++ b/sdas/linksrc/lkmain.c
@@ -212,6 +212,7 @@ main(int argc, char *argv[])
startp->f_idp = "";
pflag = 1;
+ hflag = 0;
for(i=1; i<argc; i++) {
ip = ib;
@@ -979,6 +980,11 @@ parse()
}
return(0);
+ case 'h':
+ case 'H':
+ hflag = 1;
+ break;
+
case 'I':
if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
iramsav();
diff --git a/sdas/linksrc/lkrloc3.c b/sdas/linksrc/lkrloc3.c
index b330184..0a83e0f 100644
--- a/sdas/linksrc/lkrloc3.c
+++ b/sdas/linksrc/lkrloc3.c
@@ -31,6 +31,7 @@
*/
#include "aslink.h"
+#include "lkrrel.h"
/*)Module lkrloc3.c
*
@@ -332,6 +333,9 @@ relr3(void)
* Do remaining relocations
*/
while (more()) {
+ int output_relocation_record;
+ int raddr;
+
error = 0;
mode = (int) eval();
@@ -390,6 +394,93 @@ relr3(void)
reli -= paga + pags;
}
+ /* KevT 28-05-2005 */
+
+ if (hflag)
+ {
+ output_relocation_record = 0;
+ if (mode & R3_SYM)
+ {
+ /* If the symbol is defined in a absolute area, then we do not
+ output a record. This allows us to reference absolute addresses
+ in our code, but it can still be relocated */
+
+ /* If the symbol is relative, it is within our relocatable program */
+
+ /* printf("Symbol: %s\n",s[rindex]->s_id); */
+ if ((s[rindex]->s_axp->a_bap->a_flag & A4_ABS)==0)
+ {
+ output_relocation_record=1;
+ }
+ }
+ else
+ {
+ /* If the area is absolute then we do not output a record.
+ This allows us to reference absolute memory, but still the code
+ can be relocated. */
+ /* If the area is relative, it refers to data that is part of the
+ relocatable program */
+
+ /* printf("Area: %s\n",a[rindex]->a_bap->a_id); */
+ if ((a[rindex]->a_bap->a_flag & A4_ABS)==0)
+ {
+ output_relocation_record=1;
+ }
+ }
+
+ if (output_relocation_record)
+ {
+ a_uint relocate_address = pc+(rtp-rtofst);
+ if (hilo)
+ {
+ raddr = reli + ((rtval[rtp]&0x0ff)<<8) + (rtval[rtp+1]&0x0ff);
+ }
+ else
+ {
+ raddr = reli + ((rtval[rtp+1]&0x0ff)<<8) + (rtval[rtp]&0x0ff);
+ }
+ /*printf("Relocation modify address: %04x\n",relocate_address); */
+ /*printf("Relocation address: %04x\n",raddr); */
+ if (mode & R3_BYTE)
+ {
+ if (mode & R3_BYTX)
+ {
+ if (mode & R3_MSB)
+ {
+
+relrec8hi(relocate_address,raddr);
+ }
+ else
+ {
+
+relrec8lo(relocate_address,raddr);
+ }
+ }
+ else
+ {
+ printf("not supported");
+ }
+ }
+ else
+ {
+ if (mode & R3_BYTX)
+ {
+ if (mode & R3_MSB)
+ {
+ printf("not supported");
+ }
+ else
+ {
+ printf("not supported");
+ }
+ }
+ else
+ {
+ relrec16(relocate_address);
+ }
+ }
+ }
+ }
/* pdk instruction fusion */
if (TARGET_IS_PDK) {
@@ -856,6 +947,12 @@ rele3()
if (uflag != 0) {
lkulist(0);
}
+
+ /* output relocation data */
+ if (hflag) {
+ relrecwrite();
+ }
+
if (oflag != 0) {
lkflush();
lkfclose();
diff --git a/sdas/linksrc/lkrrel.c b/sdas/linksrc/lkrrel.c
new file mode 100644
index 0000000..0d9f943
--- /dev/null
+++ b/sdas/linksrc/lkrrel.c
@@ -0,0 +1,256 @@
+/* (c) Kevin Thacker, May 2005 */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "aslink.h"
+#include "lkrrel.h"
+
+struct relrechead
+{
+ int count;
+ struct relrec *head;
+};
+
+/* 16-bit values, add full 16-bit base address */
+
+static struct relrechead head16= {0,NULL};
+/* 8-bit, but add high byte of 16-bit base address */
+static struct relrechead head8hi = {0,NULL};
+/* 8-bit, but add low byte of 16-bit base address */
+static struct relrechead head8lo = {0,NULL};
+
+/* internal; free's list */
+static void relrecfree(struct relrechead *head)
+{
+ struct relrec *cur = head->head;
+
+ while (cur!=NULL)
+ {
+ struct relrec *next = cur->next;
+ free(cur);
+
+ cur = next;
+ }
+}
+
+/* free relocation record list; e.g. on exit */
+void freerelrec()
+{
+ relrecfree(&head16);
+ relrecfree(&head8hi);
+ relrecfree(&head8lo);
+}
+
+/* internal; allocate a relocation record */
+static void newrelrec(struct relrechead *head, a_uint addr, a_uint symaddr)
+{
+ struct relrec *rec;
+
+ rec = (struct relrec *) malloc(sizeof(struct relrec));
+
+ /* error if allocation failed */
+ if (rec==NULL)
+ return;
+
+ rec->addr = addr;
+ rec->symaddr = symaddr;
+
+ /* add to start of list */
+ rec->next = head->head;
+ head->head = rec;
+ head->count++;
+}
+
+/* add item to 16-bit relocation record list */
+void relrec16(a_uint addr)
+{
+ newrelrec(&head16, addr,0);
+}
+
+/* add item to 8-bit (high) relocation record list */
+void relrec8hi(a_uint addr, a_uint symaddr)
+{
+ newrelrec(&head8hi, addr,symaddr);
+}
+
+/* add address to 8-bit (low) relocation list */
+void relrec8lo(a_uint addr, a_uint symaddr)
+{
+ newrelrec(&head8lo, addr,symaddr);
+}
+
+/* internal; compare two addresses within two relocate records */
+static int relreccompare(const void *a, const void *b)
+{
+ const struct relrec *relreca = (const struct relrec *)a;
+ const struct relrec *relrecb = (const struct relrec *)b;
+
+ return (relreca->addr-relrecb->addr);
+}
+
+/* sort a list of relocate records and return an array of the records */
+static struct relrec *relrecsort(struct relrechead *head)
+{
+ int count;
+ struct relrec *reclist;
+ struct relrec *cur;
+
+ if (head->count==0)
+ return NULL;
+
+ /* allocate list to hold all items */
+ reclist = (struct relrec *)malloc(sizeof(struct relrec)*head->count);
+
+ if (reclist==NULL)
+ return NULL;
+
+ /* fill list */
+ count = 0;
+ cur = head->head;
+ while (cur!=NULL)
+ {
+ memcpy(&reclist[count],cur,sizeof(struct relrec));
+ count++;
+ cur = cur->next;
+ }
+
+ /* sort into ascending address order */
+ qsort(reclist, count, sizeof(struct relrec),relreccompare);
+
+ return reclist;
+}
+
+int outbyte(int addr, char byte)
+{
+ rtval[0] = addr&0x0ff;
+ rtval[1] = (addr>>8)&0x0ff;
+ rtval[2] = (addr>>16)&0x0ff;
+
+ rtval[3] = byte&0x0ff;
+ addr+=1;
+ rtflg[0] = 1;
+ rtflg[1] = 1;
+ rtflg[2] = 1;
+ rtflg[3] = 1;
+ rtcnt = 4;
+ ixx(1);
+ return addr;
+}
+
+void relrecwritelist1(struct relrechead *list,int *addrptr)
+{
+ int i;
+ struct relrec *relreclist;
+ int addr;
+
+ addr = *addrptr;
+
+ relreclist = relrecsort(list);
+
+ if (relreclist!=NULL)
+ {
+ int prevaddr = 0;
+ for (i=0; i<list->count; i++)
+ {
+ struct relrec *cur = &relreclist[i];
+
+ int delta = cur->addr-prevaddr;
+
+ if (delta>254)
+ {
+ int largedelta = delta-1;
+ addr = outbyte(addr,0x0ff);
+ addr = outbyte(addr,largedelta&0x0ff);
+ addr = outbyte(addr,(largedelta>>8)&0x0ff);
+ delta = 1;
+ }
+ prevaddr = cur->addr;
+ addr = outbyte(addr,delta&0x0ff);
+ }
+
+ free(relreclist);
+ }
+
+ addr = outbyte(addr, 0);
+
+ *addrptr = addr;
+
+}
+
+void relrecwritelist2(struct relrechead *list,int *addrptr)
+{
+ int i;
+ struct relrec *relreclist;
+ int addr;
+
+ addr = *addrptr;
+
+ relreclist = relrecsort(list);
+
+ if (relreclist!=NULL)
+ {
+ int prevaddr = 0;
+ for (i=0; i<list->count; i++)
+ {
+ struct relrec *cur = &relreclist[i];
+ int delta = cur->addr-prevaddr;
+ prevaddr = cur->addr;
+
+ if (delta>254)
+ {
+ int largedelta = delta-1;
+ addr = outbyte(addr,0x0ff);
+ addr = outbyte(addr,largedelta&0x0ff);
+ addr = outbyte(addr,(largedelta>>8)&0x0ff);
+ delta = 1;
+ }
+
+ addr = outbyte(addr,delta&0x0ff);
+ addr = outbyte(addr,cur->symaddr&0x0ff);
+ }
+
+ free(relreclist);
+ }
+
+ addr = outbyte(addr,0);
+
+ *addrptr = addr;
+
+}
+
+
+void relrecwrite()
+{
+ int areasize = 0;
+
+ struct area *cur = areap;
+ while (cur!=NULL)
+ {
+ areasize+=cur->a_size;
+ cur=cur->a_ap;
+ }
+
+ //printf("total length before relocation records: %04x\n",areasize);
+
+ /* re-write offset to relocation records */
+ rtval[0] = 0;
+ rtval[1] = 0;
+ rtval[2] = 0;
+ rtval[3] = areasize&0x0ff;
+ rtval[4] = (areasize>>8)&0x0ff;
+ rtflg[0] = 1;
+ rtflg[1] = 1;
+ rtflg[2] = 1;
+ rtflg[3] = 1;
+ rtflg[4] = 1;
+ rtcnt = 5;
+ ixx(1);
+
+
+ int addr = areasize;
+
+
+ relrecwritelist1(&head16,&addr);
+ relrecwritelist1(&head8lo,&addr);
+ relrecwritelist2(&head8hi,&addr);
+}
diff --git a/sdas/linksrc/lkrrel.h b/sdas/linksrc/lkrrel.h
new file mode 100644
index 0000000..ca1cfd4
--- /dev/null
+++ b/sdas/linksrc/lkrrel.h
@@ -0,0 +1,17 @@
+/* relocation record */
+struct relrec
+{
+ /* next item */
+ struct relrec *next;
+
+ /* address of relocate */
+ a_uint addr;
+
+ a_uint symaddr;
+};
+
+void relrec16(a_uint addr);
+void relrec8lo(a_uint addr, a_uint symaddr);
+void relrec8hi(a_uint addr, a_uint symaddr);
+void freerelrec();
+void relrecwrite();
--
2.37.3