shithub: rgbds

Download patch

ref: 6ff9435e0a3a132a52816d37c9c545799c8b2eb0
parent: 40006c6152935c420b2ad2ecf1ccdfde355fa215
parent: b256e4c2e38ffe82bdfb83a7742e8bf179f32411
author: Antonio Niño Díaz <antonio_nd@outlook.com>
date: Sun May 5 19:33:36 EDT 2019

Merge pull request #335 from dbrotz/fix-334

Dynamically allocate RPN expression buffer

--- a/include/asm/rpn.h
+++ b/include/asm/rpn.h
@@ -13,7 +13,8 @@
 
 struct Expression {
 	int32_t  nVal;
-	uint8_t  tRPN[256];
+	uint8_t  *tRPN;
+	uint32_t nRPNCapacity;
 	uint32_t nRPNLength;
 	uint32_t nRPNOut;
 	uint32_t isReloc;
@@ -69,7 +70,8 @@
 void rpn_BankSymbol(struct Expression *expr, char *tzSym);
 void rpn_BankSection(struct Expression *expr, char *tzSectionName);
 void rpn_BankSelf(struct Expression *expr);
-void rpn_Reset(struct Expression *expr);
+void rpn_Init(struct Expression *expr);
+void rpn_Free(struct Expression *expr);
 void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
 
 #endif /* RGBDS_ASM_RPN_H */
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -1772,6 +1772,7 @@
 			    (!rpn_isReloc(&$2)) && ($2.nVal >= 0xFF00)) {
 				out_AbsByte(0xE0);
 				out_AbsByte($2.nVal & 0xFF);
+				rpn_Free(&$2);
 			} else {
 				out_AbsByte(0xEA);
 				out_RelWord(&$2);
@@ -1826,6 +1827,7 @@
 				    (!rpn_isReloc(&$4)) && ($4.nVal >= 0xFF00)) {
 					out_AbsByte(0xF0);
 					out_AbsByte($4.nVal & 0xFF);
+					rpn_Free(&$4);
 				} else {
 					out_AbsByte(0xFA);
 					out_RelWord(&$4);
@@ -1832,6 +1834,7 @@
 				}
 			} else {
 				yyerror("Destination operand must be A");
+				rpn_Free(&$4);
 			}
 		}
 ;
@@ -1964,6 +1967,7 @@
 				yyerror("Invalid address $%x for RST", $2.nVal);
 			else
 				out_AbsByte(0xC7 | $2.nVal);
+			rpn_Free(&$2);
 		}
 ;
 
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -782,7 +782,7 @@
 	} else {
 		out_AbsByte(expr->nVal);
 	}
-	rpn_Reset(expr);
+	rpn_Free(expr);
 }
 
 /*
@@ -825,7 +825,7 @@
 	} else {
 		out_AbsWord(expr->nVal);
 	}
-	rpn_Reset(expr);
+	rpn_Free(expr);
 }
 
 /*
@@ -871,7 +871,7 @@
 	} else {
 		out_AbsLong(expr->nVal);
 	}
-	rpn_Reset(expr);
+	rpn_Free(expr);
 }
 
 /*
@@ -892,7 +892,7 @@
 	nPC += 1;
 	pPCSymbol->nValue += 1;
 
-	rpn_Reset(expr);
+	rpn_Free(expr);
 }
 
 /*
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -10,6 +10,7 @@
  * Controls RPN expressions for objectfiles
  */
 
+#include <assert.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -24,12 +25,37 @@
 void mergetwoexpressions(struct Expression *expr, const struct Expression *src1,
 			 const struct Expression *src2)
 {
-	*expr = *src1;
-	memcpy(&(expr->tRPN[expr->nRPNLength]), src2->tRPN, src2->nRPNLength);
+	assert(src1->tRPN != NULL && src2->tRPN != NULL);
 
-	expr->nRPNLength += src2->nRPNLength;
-	expr->isReloc |= src2->isReloc;
-	expr->isPCRel |= src2->isPCRel;
+	if (src1->nRPNLength > UINT32_MAX - src2->nRPNLength)
+		fatalerror("RPN expression is too large");
+
+	uint32_t len = src1->nRPNLength + src2->nRPNLength;
+
+	expr->tRPN = src1->tRPN;
+
+	if (src1->nRPNCapacity >= len) {
+		expr->nRPNCapacity = src1->nRPNCapacity;
+	} else {
+		uint32_t cap1 = src1->nRPNCapacity;
+		uint32_t cap2 = src2->nRPNCapacity;
+		uint32_t cap = (cap1 > cap2) ? cap1 : cap2;
+
+		if (len > cap)
+			cap = (cap <= UINT32_MAX / 2) ? cap * 2 : len;
+
+		expr->nRPNCapacity = cap;
+		expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
+		if (expr->tRPN == NULL)
+			fatalerror("No memory for RPN expression");
+	}
+
+	memcpy(expr->tRPN + src1->nRPNLength, src2->tRPN, src2->nRPNLength);
+	free(src2->tRPN);
+
+	expr->nRPNLength = len;
+	expr->isReloc = src1->isReloc || src2->isReloc;
+	expr->isPCRel = src1->isPCRel || src2->isPCRel;
 }
 
 #define joinexpr() mergetwoexpressions(expr, src1, src2)
@@ -39,14 +65,29 @@
  */
 void pushbyte(struct Expression *expr, int b)
 {
+	if (expr->nRPNLength == expr->nRPNCapacity) {
+		if (expr->nRPNCapacity == 0)
+			expr->nRPNCapacity = 256;
+		else if (expr->nRPNCapacity > UINT32_MAX / 2)
+			fatalerror("RPN expression is too large");
+		else
+			expr->nRPNCapacity *= 2;
+		expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
+
+		if (expr->tRPN == NULL)
+			fatalerror("No memory for RPN expression");
+	}
+
 	expr->tRPN[expr->nRPNLength++] = b & 0xFF;
 }
 
 /*
- * Reset the RPN module
+ * Init the RPN expression
  */
-void rpn_Reset(struct Expression *expr)
+void rpn_Init(struct Expression *expr)
 {
+	expr->tRPN = NULL;
+	expr->nRPNCapacity = 0;
 	expr->nRPNLength = 0;
 	expr->nRPNOut = 0;
 	expr->isReloc = 0;
@@ -54,6 +95,15 @@
 }
 
 /*
+ * Free the RPN expression
+ */
+void rpn_Free(struct Expression *expr)
+{
+	free(expr->tRPN);
+	rpn_Init(expr);
+}
+
+/*
  * Returns the next rpn byte in expression
  */
 uint16_t rpn_PopByte(struct Expression *expr)
@@ -85,7 +135,7 @@
  */
 void rpn_Number(struct Expression *expr, uint32_t i)
 {
-	rpn_Reset(expr);
+	rpn_Init(expr);
 	pushbyte(expr, RPN_CONST);
 	pushbyte(expr, i);
 	pushbyte(expr, i >> 8);
@@ -99,7 +149,7 @@
 	if (!sym_isConstant(tzSym)) {
 		const struct sSymbol *psym;
 
-		rpn_Reset(expr);
+		rpn_Init(expr);
 
 		psym = sym_FindSymbol(tzSym);
 
@@ -118,7 +168,7 @@
 
 void rpn_BankSelf(struct Expression *expr)
 {
-	rpn_Reset(expr);
+	rpn_Init(expr);
 
 	/*
 	 * This symbol is not really relocatable, but this makes the assembler
@@ -138,7 +188,7 @@
 	}
 
 	if (!sym_isConstant(tzSym)) {
-		rpn_Reset(expr);
+		rpn_Init(expr);
 
 		/*
 		 * Check that the symbol exists by evaluating and discarding the
@@ -158,7 +208,7 @@
 
 void rpn_BankSection(struct Expression *expr, char *tzSectionName)
 {
-	rpn_Reset(expr);
+	rpn_Init(expr);
 
 	/*
 	 * This symbol is not really relocatable, but this makes the assembler