changeset 315:fcd103148aa6

Add ability to load sections downward instead of upward Add "section ... high ..." statement to link scripts to allow a section to be placed based on its end address instead of its start address. All sections listed after such a statement are treated as growing downward until the next section statement specifying a load address.
author William Astle <lost@l-w.ca>
date Wed, 27 Nov 2013 16:01:26 -0700
parents 86eb8814a05c
children c4853a54b4a1
files lwlink/link.c lwlink/lwlink.h lwlink/script.c
diffstat 3 files changed, 85 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/lwlink/link.c	Tue Nov 12 21:03:48 2013 -0700
+++ b/lwlink/link.c	Wed Nov 27 16:01:26 2013 -0700
@@ -44,7 +44,7 @@
 
 sectopt_t *section_opts = NULL;
 
-void check_section_name(char *name, int *base, fileinfo_t *fn)
+void check_section_name(char *name, int *base, fileinfo_t *fn, int down)
 {
 	int sn;
 //	fprintf(stderr, "Considering sections in %s (%d) for %s\n", fn -> filename, fn -> forced, name);
@@ -64,20 +64,28 @@
 			sectlist[nsects].ptr = &(fn -> sections[sn]);
 					
 			fn -> sections[sn].processed = 1;
-			fn -> sections[sn].loadaddress = *base;
-			*base += fn -> sections[sn].codesize;
+			if (down)
+			{
+				*base -= fn -> sections[sn].codesize;
+				fn -> sections[sn].loadaddress = *base;
+			}
+			else
+			{
+				fn -> sections[sn].loadaddress = *base;
+				*base += fn -> sections[sn].codesize;
+			}
 			nsects++;
 //			fprintf(stderr, "Adding section %s (%s)\n",fn -> sections[sn].name, fn -> filename);
 		}
 	}
 	for (sn = 0; sn < fn -> nsubs; sn++)
 	{
-		check_section_name(name, base, fn -> subs[sn]);
+		check_section_name(name, base, fn -> subs[sn], down);
 	}
 }
 
-void add_matching_sections(char *name, int yesflags, int noflags, int *base);
-void check_section_flags(int yesflags, int noflags, int *base, fileinfo_t *fn)
+void add_matching_sections(char *name, int yesflags, int noflags, int *base, int down);
+void check_section_flags(int yesflags, int noflags, int *base, fileinfo_t *fn, int down)
 {
 	int sn;
 	sectopt_t *so;
@@ -104,7 +112,7 @@
 
 		// we have a match - now collect *all* sections of the same name!
 //		fprintf(stderr, "    Found\n");
-		add_matching_sections((char *)(fn -> sections[sn].name), 0, 0, base);
+		add_matching_sections((char *)(fn -> sections[sn].name), 0, 0, base, down);
 
 		/* handle "after padding" */
 		for (so = section_opts; so; so = so -> next)
@@ -116,7 +124,15 @@
 			{
 				sectlist[nsects - 1].ptr -> afterbytes = so -> afterbytes;
 				sectlist[nsects - 1].ptr -> aftersize = so -> aftersize;
-				*base += so -> aftersize;
+				if (down)
+				{
+					sectlist[nsects - 1].ptr -> loadaddress -= so -> aftersize;
+					*base -= so -> aftersize;
+				}
+				else
+				{
+					*base += so -> aftersize;
+				}
 			}
 		}
 		
@@ -124,13 +140,13 @@
 	}
 	for (sn = 0; sn < fn -> nsubs; sn++)
 	{
-		check_section_flags(yesflags, noflags, base, fn -> subs[sn]);
+		check_section_flags(yesflags, noflags, base, fn -> subs[sn], down);
 	}
 }
 
 
 
-void add_matching_sections(char *name, int yesflags, int noflags, int *base)
+void add_matching_sections(char *name, int yesflags, int noflags, int *base, int down)
 {
 	int fn;
 	if (name)
@@ -140,7 +156,7 @@
 		// and resolve base addresses and add to the list
 		for (fn = 0; fn < ninputfiles; fn++)
 		{
-			check_section_name(name, base, inputfiles[fn]);
+			check_section_name(name, base, inputfiles[fn], down);
 		}
 	}
 	else
@@ -151,7 +167,7 @@
 		// and resolve base addresses and add to the list
 		for (fn = 0; fn < ninputfiles; fn++)
 		{
-			check_section_flags(yesflags, noflags, base, inputfiles[fn]);
+			check_section_flags(yesflags, noflags, base, inputfiles[fn], down);
 		}
 	}
 }
@@ -161,15 +177,19 @@
 void resolve_sections(void)
 {
 	int laddr = 0;
+	int growdown = 0;
 	int ln, sn, fn;
 	sectopt_t *so;
 	
 	for (ln = 0; ln < linkscript.nlines; ln++)
 	{
 		if (linkscript.lines[ln].loadat >= 0)
+		{
 			laddr = linkscript.lines[ln].loadat;
+			growdown = linkscript.lines[ln].growsdown;
+		}
 		//fprintf(stderr, "Adding section %s\n", linkscript.lines[ln].sectname);
-		add_matching_sections(linkscript.lines[ln].sectname, linkscript.lines[ln].yesflags, linkscript.lines[ln].noflags, &laddr);
+		add_matching_sections(linkscript.lines[ln].sectname, linkscript.lines[ln].yesflags, linkscript.lines[ln].noflags, &laddr, growdown);
 		
 		if (linkscript.lines[ln].sectname)
 		{
@@ -184,7 +204,15 @@
 				{
 					sectlist[nsects - 1].ptr -> afterbytes = so -> afterbytes;
 					sectlist[nsects - 1].ptr -> aftersize = so -> aftersize;
-					laddr += so -> aftersize;
+					if (growdown)
+					{
+						sectlist[nsects-1].ptr -> loadaddress -= so -> aftersize;
+						laddr -= so -> aftersize;
+					}
+					else
+					{
+						laddr += so -> aftersize;
+					}
 				}
 			}
 		}
@@ -233,13 +261,22 @@
 										f = 1;
 										sectlist[nsects].forceaddr = 1;
 										laddr = linkscript.lines[ln].loadat;
+										growdown = linkscript.lines[ln].growsdown;
 									}
 									else
 									{
 										sectlist[nsects].forceaddr = 0;
 									}
-									inputfiles[fn] -> sections[sn].loadaddress = laddr;
-									laddr += inputfiles[fn] -> sections[sn].codesize;
+									if (growdown)
+									{
+										laddr -= inputfiles[fn] -> sections[sn].codesize;
+										inputfiles[fn] -> sections[sn].loadaddress = laddr;
+									}
+									else
+									{
+										inputfiles[fn] -> sections[sn].loadaddress = laddr;
+										laddr += inputfiles[fn] -> sections[sn].codesize;
+									}
 									nsects++;
 								}
 							}
@@ -261,6 +298,8 @@
 	char sym[256];
 	int len;
 	symlist_t *se;
+	int lowaddr;
+	
 	for (sn = 0; sn < nsects; sn++)
 	{
 		if (!lastsect || strcmp(lastsect, (char *)(sectlist[sn].ptr -> name)))
@@ -275,20 +314,22 @@
 				se -> next = symlist;
 				symlist = se;
 			}
-			lastsect = (char *)(sectlist[sn].ptr -> name);
-			len = 0;
-			/* handle base symbol */
 			if (lastsect && linkscript.basesympat)
 			{
 				se = lw_alloc(sizeof(symlist_t));
-				se -> val = sectlist[sn].ptr -> loadaddress;
+				se -> val = lowaddr;
 				snprintf(sym, 255, linkscript.basesympat, lastsect);
 				se -> sym = lw_strdup(sym);
 				se -> next = symlist;
 				symlist = se;
 			}
+			lastsect = (char *)(sectlist[sn].ptr -> name);
+			len = 0;
+			lowaddr = sectlist[sn].ptr -> loadaddress;
 		}
 		len += sectlist[sn].ptr -> codesize;
+		if (sectlist[sn].ptr -> loadaddress < lowaddr)
+			lowaddr = sectlist[sn].ptr -> loadaddress;
 	}
 	if (lastsect && linkscript.lensympat)
 	{
@@ -300,7 +341,15 @@
 		se -> next = symlist;
 		symlist = se;
 	}
-
+	if (lastsect && linkscript.basesympat)
+	{
+		se = lw_alloc(sizeof(symlist_t));
+		se -> val = lowaddr;
+		snprintf(sym, 255, linkscript.basesympat, lastsect);
+		se -> sym = lw_strdup(sym);
+		se -> next = symlist;
+		symlist = se;
+	}
 }
 
 lw_expr_stack_t *find_external_sym_recurse(char *sym, fileinfo_t *fn)
--- a/lwlink/lwlink.h	Tue Nov 12 21:03:48 2013 -0700
+++ b/lwlink/lwlink.h	Wed Nov 27 16:01:26 2013 -0700
@@ -156,6 +156,7 @@
 	int loadat;					// address to load at (or -1)
 	int noflags;				// flags to NOT have
 	int yesflags;				// flags to HAVE
+	int growsdown;				// sections are placed descending in memory
 };
 
 typedef struct
--- a/lwlink/script.c	Tue Nov 12 21:03:48 2013 -0700
+++ b/lwlink/script.c	Wed Nov 27 16:01:26 2013 -0700
@@ -380,6 +380,7 @@
 		}
 		else if (!strcmp(line, "section"))
 		{
+			int growsdown = 0;
 			// section
 			// parse out the section name and flags
 			for (ptr2 = ptr; *ptr2 && !isspace(*ptr2); ptr2++)
@@ -404,12 +405,24 @@
 						ptr2++;
 					
 				}
+				else if (!strncmp(ptr2, "high", 4))
+				{
+					ptr2 += 4;
+					while (*ptr2 && isspace(*ptr2))
+						ptr2++;
+					growsdown = 1;
+				}
 				else
 				{
 					fprintf(stderr, "%s: bad script\n", scriptfile);
 					exit(1);
 				}
 			}
+			else
+			{
+				if (linkscript.nlines > 0)
+					growsdown = linkscript.lines[linkscript.nlines - 1].growsdown;
+			}
 			
 			// now ptr2 points to the load address if there is one
 			// or NUL if not
@@ -417,6 +430,7 @@
 
 			linkscript.lines[linkscript.nlines].noflags = 0;
 			linkscript.lines[linkscript.nlines].yesflags = 0;
+			linkscript.lines[linkscript.nlines].growsdown = growsdown;
 			if (*ptr2)
 				linkscript.lines[linkscript.nlines].loadat = strtol(ptr2, NULL, 16);
 			else