shithub: rgbds

Download patch

ref: a77df57f1c3a7a307409a5e73a28b9c5756204f4
parent: 8f553e89ce59944c085835b55e9d8f11283a5f63
parent: b7810ffdb3dcb5b4f4f412a0d50c5e08e146257a
author: Antonio Niño Díaz <[email protected]>
date: Tue Apr 25 09:30:30 EDT 2017

Merge pull request #177 from AntonioND/an/section-checks

Improve section size checks and buffer handling

Signed-off-by: Antonio Niño Díaz <[email protected]>

--- a/include/asm/localasm.h
+++ b/include/asm/localasm.h
@@ -80,8 +80,6 @@
 
  */
 
-#define MAXSECTIONSIZE	0x4000
-
 #define	NAME_DB			"db"
 #define	NAME_DW			"dw"
 #define	NAME_RB			"rb"
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -17,8 +17,6 @@
 #include "asm/fstack.h"
 #include "extern/err.h"
 
-#define SECTIONCHUNK	0x4000
-
 void out_SetCurrentSection(struct Section * pSect);
 
 struct Patch {
@@ -80,6 +78,24 @@
 		fatalerror("No entries in the section stack");
 }
 
+ULONG
+getmaxsectionsize(ULONG secttype, char * sectname)
+{
+	switch (secttype)
+	{
+		case SECT_ROM0:  return 0x8000; /* If ROMX sections not used. */
+		case SECT_ROMX:  return 0x4000;
+		case SECT_VRAM:  return 0x2000;
+		case SECT_SRAM:  return 0x2000;
+		case SECT_WRAM0: return 0x2000; /* If WRAMX sections not used. */
+		case SECT_WRAMX: return 0x1000;
+		case SECT_OAM:   return 0xA0;
+		case SECT_HRAM:  return 0x7F;
+		default: break;
+	}
+	errx(1, "Section \"%s\" has an invalid section type.", sectname);
+}
+
 /*
  * Count the number of symbols used in this object
  */
@@ -441,38 +457,35 @@
  * this much initialized data
  */
 void
-checkcodesection(SLONG size)
+checkcodesection(void)
 {
 	checksection();
 	if (pCurrentSection->nType != SECT_ROM0 &&
 	    pCurrentSection->nType != SECT_ROMX) {
-		errx(1, "Section '%s' cannot contain code or data (not a "
-		    "ROM0 or ROMX)", pCurrentSection->pzName);
+		fatalerror("Section '%s' cannot contain code or data (not ROM0 or ROMX)",
+		     pCurrentSection->pzName);
 	}
-	if (pCurrentSection->nPC + size > MAXSECTIONSIZE) {
+}
+
+/*
+ * Check if the section has grown too much.
+ */
+void
+checksectionoverflow(ULONG delta_size)
+{
+	ULONG maxsize = getmaxsectionsize(pCurrentSection->nType,
+					  pCurrentSection->pzName);
+
+	if (pCurrentSection->nPC + delta_size > maxsize) {
 		/*
-		 * N.B.: This check is not sufficient to ensure the section
-		 * will fit, because there can be multiple sections of this
-		 * type. The definitive check must be done at the linking
-		 * stage.
+		 * This check is here to trap broken code that generates
+		 * sections that are too big and to prevent the assembler from
+		 * generating huge object files.
+		 * The real check must be done at the linking stage.
 		 */
-		errx(1, "Section '%s' is too big (old size %d + %d > %d)",
-		    pCurrentSection->pzName, pCurrentSection->nPC, size,
-		    MAXSECTIONSIZE);
+		fatalerror("Section '%s' is too big (max size = 0x%X bytes).",
+			pCurrentSection->pzName, maxsize);
 	}
-	if (((pCurrentSection->nPC % SECTIONCHUNK) >
-	    ((pCurrentSection->nPC + size) % SECTIONCHUNK)) &&
-	    (pCurrentSection->nType == SECT_ROM0 ||
-	    pCurrentSection->nType == SECT_ROMX)) {
-		pCurrentSection->tData = realloc(pCurrentSection->tData,
-		    ((pCurrentSection->nPC + size) / SECTIONCHUNK + 1) *
-		    SECTIONCHUNK);
-
-		if (pCurrentSection->tData == NULL) {
-			err(1, "Could not expand section");
-		}
-	}
-	return;
 }
 
 /*
@@ -580,10 +593,15 @@
 			pSect->charmap = NULL;
 			pPatchSymbols = NULL;
 
-			if ((pSect->tData = malloc(SECTIONCHUNK)) != NULL) {
-				return (pSect);
-			} else
-				fatalerror("Not enough memory for section");
+			pSect->tData = NULL;
+			if (secttype == SECT_ROM0 || secttype == SECT_ROMX) {
+				/* It is only needed to allocate memory for ROM
+				 * sections. */
+				ULONG sectsize = getmaxsectionsize(secttype, pzName);
+				if ((pSect->tData = malloc(sectsize)) == NULL)
+					fatalerror("Not enough memory for section");
+			}
+			return (pSect);
 		} else
 			fatalerror("Not enough memory for sectionname");
 	} else
@@ -641,7 +659,8 @@
 void
 out_AbsByte(int b)
 {
-	checkcodesection(1);
+	checkcodesection();
+	checksectionoverflow(1);
 	b &= 0xFF;
 	if (nPass == 2)
 		pCurrentSection->tData[nPC] = b;
@@ -654,7 +673,8 @@
 void
 out_AbsByteGroup(char *s, int length)
 {
-	checkcodesection(length);
+	checkcodesection();
+	checksectionoverflow(length);
 	while (length--)
 		out_AbsByte(*s++);
 }
@@ -666,6 +686,7 @@
 out_Skip(int skip)
 {
 	checksection();
+	checksectionoverflow(skip);
 	if (!((pCurrentSection->nType == SECT_ROM0)
 		|| (pCurrentSection->nType == SECT_ROMX))) {
 		pCurrentSection->nPC += skip;
@@ -672,7 +693,7 @@
 		nPC += skip;
 		pPCSymbol->nValue += skip;
 	} else {
-		checkcodesection(skip);
+		checkcodesection();
 		while (skip--)
 			out_AbsByte(CurrentOptions.fillchar);
 	}
@@ -684,7 +705,8 @@
 void
 out_String(char *s)
 {
-	checkcodesection(strlen(s));
+	checkcodesection();
+	checksectionoverflow(strlen(s));
 	while (*s)
 		out_AbsByte(*s++);
 }
@@ -697,7 +719,8 @@
 void
 out_RelByte(struct Expression * expr)
 {
-	checkcodesection(1);
+	checkcodesection();
+	checksectionoverflow(1);
 	if (rpn_isReloc(expr)) {
 		if (nPass == 2) {
 			pCurrentSection->tData[nPC] = 0;
@@ -718,7 +741,8 @@
 void
 out_AbsWord(int b)
 {
-	checkcodesection(2);
+	checkcodesection();
+	checksectionoverflow(2);
 	b &= 0xFFFF;
 	if (nPass == 2) {
 		pCurrentSection->tData[nPC] = b & 0xFF;
@@ -738,7 +762,8 @@
 {
 	ULONG b;
 
-	checkcodesection(2);
+	checkcodesection();
+	checksectionoverflow(2);
 	b = expr->nVal & 0xFFFF;
 	if (rpn_isReloc(expr)) {
 		if (nPass == 2) {
@@ -760,7 +785,8 @@
 void
 out_AbsLong(SLONG b)
 {
-	checkcodesection(sizeof(SLONG));
+	checkcodesection();
+	checksectionoverflow(sizeof(SLONG));
 	if (nPass == 2) {
 		pCurrentSection->tData[nPC] = b & 0xFF;
 		pCurrentSection->tData[nPC + 1] = b >> 8;
@@ -781,7 +807,8 @@
 {
 	SLONG b;
 
-	checkcodesection(4);
+	checkcodesection();
+	checksectionoverflow(4);
 	b = expr->nVal;
 	if (rpn_isReloc(expr)) {
 		if (nPass == 2) {
@@ -807,7 +834,8 @@
 {
 	SLONG b = expr->nVal;
 
-	checkcodesection(1);
+	checkcodesection();
+	checksectionoverflow(1);
 	b = (b & 0xFFFF) - (nPC + 1);
 	if (nPass == 2 && (b < -128 || b > 127))
 		yyerror("PC-relative value must be 8-bit");
@@ -835,7 +863,8 @@
 	fsize = ftell(f);
 	fseek(f, 0, SEEK_SET);
 
-	checkcodesection(fsize);
+	checkcodesection();
+	checksectionoverflow(fsize);
 
 	if (nPass == 2) {
 		SLONG dest = nPC;
@@ -879,7 +908,8 @@
 
 	fseek(f, start_pos, SEEK_SET);
 
-	checkcodesection(length);
+	checkcodesection();
+	checksectionoverflow(length);
 
 	if (nPass == 2) {
 		SLONG dest = nPC;
--- a/src/link/object.c
+++ b/src/link/object.c
@@ -169,6 +169,42 @@
 		}
 	}
 
+	unsigned int maxsize = 0;
+
+	/* Verify that the section isn't too big */
+	switch (pSection->Type)
+	{
+		case SECT_ROM0:
+			maxsize = (options & OPT_TINY) ? 0x8000 : 0x4000;
+			break;
+		case SECT_ROMX:
+			maxsize = 0x4000;
+			break;
+		case SECT_VRAM:
+		case SECT_SRAM:
+			maxsize = 0x2000;
+			break;
+		case SECT_WRAM0:
+			maxsize = (options & OPT_CONTWRAM) ? 0x2000 : 0x1000;
+			break;
+		case SECT_WRAMX:
+			maxsize = 0x1000;
+			break;
+		case SECT_OAM:
+			maxsize = 0xA0;
+			break;
+		case SECT_HRAM:
+			maxsize = 0x7F;
+			break;
+		default:
+			errx(1, "Section \"%s\" has an invalid section type.", pzName);
+			break;
+	}
+	if (pSection->nByteSize > maxsize) {
+		errx(1, "Section \"%s\" is bigger than the max size for that type: 0x%X > 0x%X",
+			pzName, pSection->nByteSize, maxsize);
+	}
+
 	if ((pSection->Type == SECT_ROMX) || (pSection->Type == SECT_ROM0)) {
 		/*
 		 * These sectiontypes contain data...