shithub: rgbds

Download patch

ref: d0ec35628f753d7fe783b6971ad91fb570caea76
parent: bfdbd000927825cb9bb68d9802ddf95f19c6a35e
author: ISSOtm <[email protected]>
date: Mon Feb 3 18:26:00 EST 2020

Split section management into its own file

--- a/Makefile
+++ b/Makefile
@@ -61,6 +61,7 @@
 	src/asm/math.o \
 	src/asm/output.o \
 	src/asm/rpn.o \
+	src/asm/section.o \
 	src/asm/symbol.o \
 	src/asm/util.o \
 	src/asm/warning.o \
--- a/include/asm/output.h
+++ b/include/asm/output.h
@@ -11,45 +11,16 @@
 
 #include <stdint.h>
 
-#include "asm/rpn.h"
-
 #include "linkdefs.h"
 
-struct Section {
-	char *pzName;
-	enum SectionType nType;
-	uint32_t nPC;
-	uint32_t nOrg;
-	uint32_t nBank;
-	uint32_t nAlign;
-	struct Section *pNext;
-	struct Patch *pPatches;
-	uint8_t *tData;
-};
+struct Expression;
 
 extern char *tzObjectname;
+extern struct Section *pSectionList, *pCurrentSection;
 
 void out_PrepPass2(void);
 void out_SetFileName(char *s);
-struct Section *out_FindSectionByName(const char *pzName);
-void out_NewSection(char *pzName, uint32_t secttype);
-void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
-		       int32_t bank);
-void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
-			   int32_t bank);
-void out_AbsByte(int32_t b);
-void out_AbsByteGroup(char *s, int32_t length);
-void out_RelByte(struct Expression *expr);
-void out_RelWord(struct Expression *expr);
-void out_PCRelByte(struct Expression *expr);
+void out_CreatePatch(uint32_t type, struct Expression *expr);
 void out_WriteObject(void);
-void out_Skip(int32_t skip);
-void out_BinaryFile(char *s);
-void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length);
-void out_String(char *s);
-void out_AbsLong(int32_t b);
-void out_RelLong(struct Expression *expr);
-void out_PushSection(void);
-void out_PopSection(void);
 
 #endif /* RGBDS_ASM_OUTPUT_H */
--- /dev/null
+++ b/include/asm/section.h
@@ -1,0 +1,39 @@
+
+#include <stdint.h>
+
+#include "linkdefs.h"
+
+struct Expression;
+
+struct Section {
+	char *pzName;
+	enum SectionType nType;
+	uint32_t nPC;
+	uint32_t nOrg;
+	uint32_t nBank;
+	uint32_t nAlign;
+	struct Section *pNext;
+	struct Patch *pPatches;
+	uint8_t *tData;
+};
+
+struct Section *out_FindSectionByName(const char *pzName);
+void out_NewSection(char *pzName, uint32_t secttype);
+void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
+		       int32_t bank);
+void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
+			   int32_t bank);
+
+void out_AbsByte(int32_t b);
+void out_AbsByteGroup(char *s, int32_t length);
+void out_Skip(int32_t skip);
+void out_String(char *s);
+void out_RelByte(struct Expression *expr);
+void out_RelWord(struct Expression *expr);
+void out_RelLong(struct Expression *expr);
+void out_PCRelByte(struct Expression *expr);
+void out_BinaryFile(char *s);
+void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length);
+
+void out_PushSection(void);
+void out_PopSection(void);
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -22,8 +22,8 @@
 #include "asm/lexer.h"
 #include "asm/main.h"
 #include "asm/mymath.h"
-#include "asm/output.h"
 #include "asm/rpn.h"
+#include "asm/section.h"
 #include "asm/symbol.h"
 #include "asm/util.h"
 #include "asm/warning.h"
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -40,6 +40,7 @@
 #include "asm/main.h"
 #include "asm/output.h"
 #include "asm/rpn.h"
+#include "asm/section.h"
 #include "asm/symbol.h"
 #include "asm/warning.h"
 
@@ -47,8 +48,6 @@
 
 #include "linkdefs.h"
 
-void out_SetCurrentSection(struct Section *pSect);
-
 struct Patch {
 	char tzFilename[_MAX_PATH + 1];
 	uint32_t nLine;
@@ -66,51 +65,13 @@
 	struct PatchSymbol *pBucketNext; /* next symbol in hash table bucket */
 };
 
-struct SectionStackEntry {
-	struct Section *pSection;
-	struct sSymbol *pScope; /* Section's symbol scope */
-	struct SectionStackEntry *pNext;
-};
-
 struct PatchSymbol *tHashedPatchSymbols[HASHSIZE];
 struct Section *pSectionList, *pCurrentSection;
 struct PatchSymbol *pPatchSymbols;
 struct PatchSymbol **ppPatchSymbolsTail = &pPatchSymbols;
 char *tzObjectname;
-struct SectionStackEntry *pSectionStack;
 
 /*
- * Section stack routines
- */
-void out_PushSection(void)
-{
-	struct SectionStackEntry *pSect;
-
-	pSect = malloc(sizeof(struct SectionStackEntry));
-	if (pSect == NULL)
-		fatalerror("No memory for section stack");
-
-	pSect->pSection = pCurrentSection;
-	pSect->pScope = sym_GetCurrentSymbolScope();
-	pSect->pNext = pSectionStack;
-	pSectionStack = pSect;
-}
-
-void out_PopSection(void)
-{
-	if (pSectionStack == NULL)
-		fatalerror("No entries in the section stack");
-
-	struct SectionStackEntry *pSect;
-
-	pSect = pSectionStack;
-	out_SetCurrentSection(pSect->pSection);
-	sym_SetCurrentSymbolScope(pSect->pScope);
-	pSectionStack = pSect->pNext;
-	free(pSect);
-}
-
-/*
  * Count the number of symbols used in this object
  */
 static uint32_t countsymbols(void)
@@ -368,7 +329,7 @@
 /*
  * Create a new patch (includes the rpn expr)
  */
-void createpatch(uint32_t type, struct Expression *expr)
+void out_CreatePatch(uint32_t type, struct Expression *expr)
 {
 	struct Patch *pPatch;
 	uint16_t rpndata;
@@ -470,51 +431,6 @@
 }
 
 /*
- * A quick check to see if we have an initialized section
- */
-static void checksection(void)
-{
-	if (pCurrentSection == NULL)
-		fatalerror("Code generation before SECTION directive");
-}
-
-/*
- * A quick check to see if we have an initialized section that can contain
- * this much initialized data
- */
-static void checkcodesection(void)
-{
-	checksection();
-
-	if (!sect_HasData(pCurrentSection->nType))
-		fatalerror("Section '%s' cannot contain code or data (not ROM0 or ROMX)",
-			   pCurrentSection->pzName);
-	else if (nUnionDepth > 0)
-		fatalerror("UNIONs cannot contain code or data");
-}
-
-/*
- * Check if the section has grown too much.
- */
-static void checksectionoverflow(uint32_t delta_size)
-{
-	uint32_t maxSize = maxsize[pCurrentSection->nType];
-	uint32_t newSize = pCurrentSection->nPC + delta_size;
-
-	if (newSize > maxSize) {
-		/*
-		 * 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 or trying to allocate too much
-		 * memory.
-		 * The real check must be done at the linking stage.
-		 */
-		fatalerror("Section '%s' is too big (max size = 0x%X bytes, reached 0x%X).",
-			   pCurrentSection->pzName, maxSize, newSize);
-	}
-}
-
-/*
  * Write an objectfile
  */
 void out_WriteObject(void)
@@ -575,394 +491,4 @@
 	tzObjectname = s;
 	if (CurrentOptions.verbose)
 		printf("Output filename %s\n", s);
-}
-
-struct Section *out_FindSectionByName(const char *pzName)
-{
-	struct Section *pSect = pSectionList;
-
-	while (pSect) {
-		if (strcmp(pzName, pSect->pzName) == 0)
-			return pSect;
-
-		pSect = pSect->pNext;
-	}
-
-	return NULL;
-}
-
-/*
- * Find a section by name and type. If it doesn't exist, create it
- */
-struct Section *out_FindSection(char *pzName, enum SectionType secttype,
-				int32_t org, int32_t bank, int32_t alignment)
-{
-	struct Section *pSect = out_FindSectionByName(pzName);
-
-	if (pSect) {
-		if (secttype == pSect->nType
-			&& ((uint32_t)org) == pSect->nOrg
-			&& ((uint32_t)bank) == pSect->nBank
-			&& ((uint32_t)alignment == pSect->nAlign)) {
-			return pSect;
-		}
-		fatalerror("Section already exists but with a different type");
-	}
-
-	pSect = malloc(sizeof(*pSect));
-	if (pSect == NULL)
-		fatalerror("Not enough memory for section");
-
-	pSect->pzName = strdup(pzName);
-	if (pSect->pzName == NULL)
-		fatalerror("Not enough memory for sectionname");
-
-	if (nbbanks(secttype) == 1)
-		bank = bankranges[secttype][0];
-
-	pSect->nType = secttype;
-	pSect->nPC = 0;
-	pSect->nOrg = org;
-	pSect->nBank = bank;
-	pSect->nAlign = alignment;
-	pSect->pNext = pSectionList;
-	pSect->pPatches = NULL;
-
-	/* It is only needed to allocate memory for ROM sections. */
-	if (sect_HasData(secttype)) {
-		uint32_t sectsize;
-
-		sectsize = maxsize[secttype];
-		pSect->tData = malloc(sectsize);
-		if (pSect->tData == NULL)
-			fatalerror("Not enough memory for section");
-	} else {
-		pSect->tData = NULL;
-	}
-
-	/*
-	 * Add the new section to the list
-	 * at the beginning because order doesn't matter
-	 */
-	pSectionList = pSect;
-
-	return pSect;
-}
-
-/*
- * Set the current section
- */
-void out_SetCurrentSection(struct Section *pSect)
-{
-	if (nUnionDepth > 0)
-		fatalerror("Cannot change the section within a UNION");
-
-	pCurrentSection = pSect;
-	nPC = (pSect != NULL) ? pSect->nPC : 0;
-
-	pPCSymbol->nValue = nPC;
-	pPCSymbol->pSection = pCurrentSection;
-	pPCSymbol->isConstant = pSect && pSect->nOrg != -1;
-}
-
-/*
- * Set the current section by name and type
- */
-void out_NewSection(char *pzName, uint32_t secttype)
-{
-	out_SetCurrentSection(out_FindSection(pzName, secttype, -1, -1, 1));
-}
-
-/*
- * Set the current section by name and type
- */
-void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
-		       int32_t bank)
-{
-	out_SetCurrentSection(out_FindSection(pzName, secttype, org, bank, 1));
-}
-
-/*
- * Set the current section by name and type, using a given byte alignment
- */
-void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
-			   int32_t bank)
-{
-	if (alignment < 0 || alignment > 16)
-		yyerror("Alignment must be between 0-16 bits.");
-
-	out_SetCurrentSection(out_FindSection(pzName, secttype, -1, bank,
-					      1 << alignment));
-}
-
-/*
- * Output an absolute byte (bypassing ROM/union checks)
- */
-void out_AbsByteBypassCheck(int32_t b)
-{
-	checksectionoverflow(1);
-	b &= 0xFF;
-	pCurrentSection->tData[nPC] = b;
-	pCurrentSection->nPC++;
-	nPC++;
-	pPCSymbol->nValue++;
-}
-
-/*
- * Output an absolute byte
- */
-void out_AbsByte(int32_t b)
-{
-	checkcodesection();
-	out_AbsByteBypassCheck(b);
-}
-
-void out_AbsByteGroup(char *s, int32_t length)
-{
-	checkcodesection();
-	checksectionoverflow(length);
-	while (length--)
-		out_AbsByte(*s++);
-}
-
-/*
- * Skip this many bytes
- */
-void out_Skip(int32_t skip)
-{
-	checksection();
-	checksectionoverflow(skip);
-	if (!sect_HasData(pCurrentSection->nType)) {
-		pCurrentSection->nPC += skip;
-		nPC += skip;
-		pPCSymbol->nValue += skip;
-	} else if (nUnionDepth > 0) {
-		while (skip--)
-			out_AbsByteBypassCheck(CurrentOptions.fillchar);
-	} else {
-		checkcodesection();
-		while (skip--)
-			out_AbsByte(CurrentOptions.fillchar);
-	}
-}
-
-/*
- * Output a NULL terminated string (excluding the NULL-character)
- */
-void out_String(char *s)
-{
-	checkcodesection();
-	checksectionoverflow(strlen(s));
-	while (*s)
-		out_AbsByte(*s++);
-}
-
-/*
- * Output a relocatable byte. Checking will be done to see if it
- * is an absolute value in disguise.
- */
-void out_RelByte(struct Expression *expr)
-{
-	checkcodesection();
-	checksectionoverflow(1);
-	if (!rpn_isKnown(expr)) {
-		pCurrentSection->tData[nPC] = 0;
-		createpatch(PATCHTYPE_BYTE, expr);
-		pCurrentSection->nPC++;
-		nPC++;
-		pPCSymbol->nValue++;
-	} else {
-		out_AbsByte(expr->nVal);
-	}
-	rpn_Free(expr);
-}
-
-/*
- * Output an absolute word
- */
-void out_AbsWord(int32_t b)
-{
-	checkcodesection();
-	checksectionoverflow(2);
-	b &= 0xFFFF;
-	pCurrentSection->tData[nPC] = b & 0xFF;
-	pCurrentSection->tData[nPC + 1] = b >> 8;
-	pCurrentSection->nPC += 2;
-	nPC += 2;
-	pPCSymbol->nValue += 2;
-}
-
-/*
- * Output a relocatable word. Checking will be done to see if
- * it's an absolute value in disguise.
- */
-void out_RelWord(struct Expression *expr)
-{
-	checkcodesection();
-	checksectionoverflow(2);
-	if (!rpn_isKnown(expr)) {
-		pCurrentSection->tData[nPC] = 0;
-		pCurrentSection->tData[nPC + 1] = 0;
-		createpatch(PATCHTYPE_WORD, expr);
-		pCurrentSection->nPC += 2;
-		nPC += 2;
-		pPCSymbol->nValue += 2;
-	} else {
-		out_AbsWord(expr->nVal);
-	}
-	rpn_Free(expr);
-}
-
-/*
- * Output an absolute longword
- */
-void out_AbsLong(int32_t b)
-{
-	checkcodesection();
-	checksectionoverflow(sizeof(int32_t));
-	pCurrentSection->tData[nPC] = b & 0xFF;
-	pCurrentSection->tData[nPC + 1] = b >> 8;
-	pCurrentSection->tData[nPC + 2] = b >> 16;
-	pCurrentSection->tData[nPC + 3] = b >> 24;
-	pCurrentSection->nPC += 4;
-	nPC += 4;
-	pPCSymbol->nValue += 4;
-}
-
-/*
- * Output a relocatable longword. Checking will be done to see if
- * is an absolute value in disguise.
- */
-void out_RelLong(struct Expression *expr)
-{
-	checkcodesection();
-	checksectionoverflow(4);
-	if (!rpn_isKnown(expr)) {
-		pCurrentSection->tData[nPC] = 0;
-		pCurrentSection->tData[nPC + 1] = 0;
-		pCurrentSection->tData[nPC + 2] = 0;
-		pCurrentSection->tData[nPC + 3] = 0;
-		createpatch(PATCHTYPE_LONG, expr);
-		pCurrentSection->nPC += 4;
-		nPC += 4;
-		pPCSymbol->nValue += 4;
-	} else {
-		out_AbsLong(expr->nVal);
-	}
-	rpn_Free(expr);
-}
-
-/*
- * Output a PC-relative relocatable byte. Checking will be done to see if it
- * is an absolute value in disguise.
- */
-void out_PCRelByte(struct Expression *expr)
-{
-	checkcodesection();
-	checksectionoverflow(1);
-	if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) {
-		pCurrentSection->tData[nPC] = 0;
-		createpatch(PATCHTYPE_JR, expr);
-		pCurrentSection->nPC++;
-		nPC++;
-		pPCSymbol->nValue++;
-	} else {
-		/* Target is relative to the byte *after* the operand */
-		uint16_t address = pCurrentSection->nOrg + nPC + 1;
-		/* The offset wraps (jump from ROM to HRAM, for loopexample) */
-		int16_t offset = expr->nVal - address;
-
-		if (offset < -128 || offset > 127) {
-			yyerror("jr target out of reach (expected -129 < %d < 128)", offset);
-			out_AbsByte(0);
-		} else {
-			out_AbsByte(offset);
-		}
-	}
-	rpn_Free(expr);
-}
-
-/*
- * Output a binary file
- */
-void out_BinaryFile(char *s)
-{
-	FILE *f;
-
-	f = fstk_FindFile(s, NULL);
-	if (f == NULL) {
-		if (oGeneratedMissingIncludes) {
-			oFailedOnMissingInclude = true;
-			return;
-		}
-		err(1, "Unable to open incbin file '%s'", s);
-	}
-
-	int32_t fsize;
-
-	fseek(f, 0, SEEK_END);
-	fsize = ftell(f);
-	fseek(f, 0, SEEK_SET);
-
-	checkcodesection();
-	checksectionoverflow(fsize);
-
-	int32_t dest = nPC;
-	int32_t todo = fsize;
-
-	while (todo--)
-		pCurrentSection->tData[dest++] = fgetc(f);
-
-	pCurrentSection->nPC += fsize;
-	nPC += fsize;
-	pPCSymbol->nValue += fsize;
-	fclose(f);
-}
-
-void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length)
-{
-	FILE *f;
-
-	if (start_pos < 0)
-		fatalerror("Start position cannot be negative");
-
-	if (length < 0)
-		fatalerror("Number of bytes to read must be greater than zero");
-
-	f = fstk_FindFile(s, NULL);
-	if (f == NULL) {
-		if (oGeneratedMissingIncludes) {
-			oFailedOnMissingInclude = true;
-			return;
-		}
-		err(1, "Unable to open included file '%s'", s);
-	}
-
-	int32_t fsize;
-
-	fseek(f, 0, SEEK_END);
-	fsize = ftell(f);
-
-	if (start_pos >= fsize)
-		fatalerror("Specified start position is greater than length of file");
-
-	if ((start_pos + length) > fsize)
-		fatalerror("Specified range in INCBIN is out of bounds");
-
-	fseek(f, start_pos, SEEK_SET);
-
-	checkcodesection();
-	checksectionoverflow(length);
-
-	int32_t dest = nPC;
-	int32_t todo = length;
-
-	while (todo--)
-		pCurrentSection->tData[dest++] = fgetc(f);
-
-	pCurrentSection->nPC += length;
-	nPC += length;
-	pPCSymbol->nValue += length;
-
-	fclose(f);
 }
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -19,8 +19,8 @@
 #include "asm/asm.h"
 #include "asm/main.h"
 #include "asm/rpn.h"
+#include "asm/section.h"
 #include "asm/symbol.h"
-#include "asm/output.h"
 #include "asm/warning.h"
 
 /* Makes an expression "not known", also setting its error message */
--- /dev/null
+++ b/src/asm/section.c
@@ -1,0 +1,487 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "asm/fstack.h"
+#include "asm/main.h"
+#include "asm/output.h"
+#include "asm/rpn.h"
+#include "asm/section.h"
+#include "asm/warning.h"
+
+#include "extern/err.h"
+
+struct SectionStackEntry {
+	struct Section *pSection;
+	struct sSymbol *pScope; /* Section's symbol scope */
+	struct SectionStackEntry *pNext;
+};
+
+struct SectionStackEntry *pSectionStack;
+
+/*
+ * A quick check to see if we have an initialized section
+ */
+static void checksection(void)
+{
+	if (pCurrentSection == NULL)
+		fatalerror("Code generation before SECTION directive");
+}
+
+/*
+ * A quick check to see if we have an initialized section that can contain
+ * this much initialized data
+ */
+static void checkcodesection(void)
+{
+	checksection();
+
+	if (!sect_HasData(pCurrentSection->nType))
+		fatalerror("Section '%s' cannot contain code or data (not ROM0 or ROMX)",
+			   pCurrentSection->pzName);
+	else if (nUnionDepth > 0)
+		fatalerror("UNIONs cannot contain code or data");
+}
+
+/*
+ * Check if the section has grown too much.
+ */
+static void checksectionoverflow(uint32_t delta_size)
+{
+	uint32_t maxSize = maxsize[pCurrentSection->nType];
+	uint32_t newSize = pCurrentSection->nPC + delta_size;
+
+	if (newSize > maxSize) {
+		/*
+		 * 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 or trying to allocate too much
+		 * memory.
+		 * The real check must be done at the linking stage.
+		 */
+		fatalerror("Section '%s' is too big (max size = 0x%X bytes, reached 0x%X).",
+			   pCurrentSection->pzName, maxSize, newSize);
+	}
+}
+
+struct Section *out_FindSectionByName(const char *pzName)
+{
+	struct Section *pSect = pSectionList;
+
+	while (pSect) {
+		if (strcmp(pzName, pSect->pzName) == 0)
+			return pSect;
+
+		pSect = pSect->pNext;
+	}
+
+	return NULL;
+}
+
+/*
+ * Find a section by name and type. If it doesn't exist, create it
+ */
+static struct Section *findSection(char *pzName, enum SectionType secttype,
+				   int32_t org, int32_t bank, int32_t alignment)
+{
+	struct Section *pSect = out_FindSectionByName(pzName);
+
+	if (pSect) {
+		if (secttype == pSect->nType
+			&& ((uint32_t)org) == pSect->nOrg
+			&& ((uint32_t)bank) == pSect->nBank
+			&& ((uint32_t)alignment == pSect->nAlign)) {
+			return pSect;
+		}
+		fatalerror("Section already exists but with a different type");
+	}
+
+	pSect = malloc(sizeof(*pSect));
+	if (pSect == NULL)
+		fatalerror("Not enough memory for section");
+
+	pSect->pzName = strdup(pzName);
+	if (pSect->pzName == NULL)
+		fatalerror("Not enough memory for sectionname");
+
+	if (nbbanks(secttype) == 1)
+		bank = bankranges[secttype][0];
+
+	pSect->nType = secttype;
+	pSect->nPC = 0;
+	pSect->nOrg = org;
+	pSect->nBank = bank;
+	pSect->nAlign = alignment;
+	pSect->pNext = pSectionList;
+	pSect->pPatches = NULL;
+
+	/* It is only needed to allocate memory for ROM sections. */
+	if (sect_HasData(secttype)) {
+		uint32_t sectsize;
+
+		sectsize = maxsize[secttype];
+		pSect->tData = malloc(sectsize);
+		if (pSect->tData == NULL)
+			fatalerror("Not enough memory for section");
+	} else {
+		pSect->tData = NULL;
+	}
+
+	/*
+	 * Add the new section to the list
+	 * at the beginning because order doesn't matter
+	 */
+	pSectionList = pSect;
+
+	return pSect;
+}
+
+/*
+ * Set the current section
+ */
+static void setCurrentSection(struct Section *pSect)
+{
+	if (nUnionDepth > 0)
+		fatalerror("Cannot change the section within a UNION");
+
+	pCurrentSection = pSect;
+	nPC = (pSect != NULL) ? pSect->nPC : 0;
+
+	pPCSymbol->nValue = nPC;
+	pPCSymbol->pSection = pCurrentSection;
+	pPCSymbol->isConstant = pSect && pSect->nOrg != -1;
+}
+
+/*
+ * Set the current section by name and type
+ */
+void out_NewSection(char *pzName, uint32_t secttype)
+{
+	setCurrentSection(findSection(pzName, secttype, -1, -1, 1));
+}
+
+/*
+ * Set the current section by name and type
+ */
+void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
+		       int32_t bank)
+{
+	setCurrentSection(findSection(pzName, secttype, org, bank, 1));
+}
+
+/*
+ * Set the current section by name and type, using a given byte alignment
+ */
+void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
+			   int32_t bank)
+{
+	if (alignment < 0 || alignment > 16)
+		yyerror("Alignment must be between 0-16 bits.");
+
+	setCurrentSection(findSection(pzName, secttype, -1, bank,
+				      1 << alignment));
+}
+
+/*
+ * Output an absolute byte (bypassing ROM/union checks)
+ */
+static void absByteBypassCheck(int32_t b)
+{
+	checksectionoverflow(1);
+	b &= 0xFF;
+	pCurrentSection->tData[nPC] = b;
+	pCurrentSection->nPC++;
+	nPC++;
+	pPCSymbol->nValue++;
+}
+
+/*
+ * Output an absolute byte
+ */
+void out_AbsByte(int32_t b)
+{
+	checkcodesection();
+	absByteBypassCheck(b);
+}
+
+void out_AbsByteGroup(char *s, int32_t length)
+{
+	checkcodesection();
+	checksectionoverflow(length);
+	while (length--)
+		out_AbsByte(*s++);
+}
+
+/*
+ * Skip this many bytes
+ */
+void out_Skip(int32_t skip)
+{
+	checksection();
+	checksectionoverflow(skip);
+	if (!sect_HasData(pCurrentSection->nType)) {
+		pCurrentSection->nPC += skip;
+		nPC += skip;
+		pPCSymbol->nValue += skip;
+	} else if (nUnionDepth > 0) {
+		while (skip--)
+			absByteBypassCheck(CurrentOptions.fillchar);
+	} else {
+		checkcodesection();
+		while (skip--)
+			out_AbsByte(CurrentOptions.fillchar);
+	}
+}
+
+/*
+ * Output a NULL terminated string (excluding the NULL-character)
+ */
+void out_String(char *s)
+{
+	checkcodesection();
+	checksectionoverflow(strlen(s));
+	while (*s)
+		out_AbsByte(*s++);
+}
+
+/*
+ * Output a relocatable byte. Checking will be done to see if it
+ * is an absolute value in disguise.
+ */
+void out_RelByte(struct Expression *expr)
+{
+	checkcodesection();
+	checksectionoverflow(1);
+	if (!rpn_isKnown(expr)) {
+		pCurrentSection->tData[nPC] = 0;
+		out_CreatePatch(PATCHTYPE_BYTE, expr);
+		pCurrentSection->nPC++;
+		nPC++;
+		pPCSymbol->nValue++;
+	} else {
+		out_AbsByte(expr->nVal);
+	}
+	rpn_Free(expr);
+}
+
+/*
+ * Output an absolute word
+ */
+static void absWord(int32_t b)
+{
+	checkcodesection();
+	checksectionoverflow(2);
+	b &= 0xFFFF;
+	pCurrentSection->tData[nPC] = b & 0xFF;
+	pCurrentSection->tData[nPC + 1] = b >> 8;
+	pCurrentSection->nPC += 2;
+	nPC += 2;
+	pPCSymbol->nValue += 2;
+}
+
+/*
+ * Output a relocatable word. Checking will be done to see if
+ * it's an absolute value in disguise.
+ */
+void out_RelWord(struct Expression *expr)
+{
+	checkcodesection();
+	checksectionoverflow(2);
+	if (!rpn_isKnown(expr)) {
+		pCurrentSection->tData[nPC] = 0;
+		pCurrentSection->tData[nPC + 1] = 0;
+		out_CreatePatch(PATCHTYPE_WORD, expr);
+		pCurrentSection->nPC += 2;
+		nPC += 2;
+		pPCSymbol->nValue += 2;
+	} else {
+		absWord(expr->nVal);
+	}
+	rpn_Free(expr);
+}
+
+/*
+ * Output an absolute longword
+ */
+static void absLong(int32_t b)
+{
+	checkcodesection();
+	checksectionoverflow(sizeof(int32_t));
+	pCurrentSection->tData[nPC] = b & 0xFF;
+	pCurrentSection->tData[nPC + 1] = b >> 8;
+	pCurrentSection->tData[nPC + 2] = b >> 16;
+	pCurrentSection->tData[nPC + 3] = b >> 24;
+	pCurrentSection->nPC += 4;
+	nPC += 4;
+	pPCSymbol->nValue += 4;
+}
+
+/*
+ * Output a relocatable longword. Checking will be done to see if
+ * is an absolute value in disguise.
+ */
+void out_RelLong(struct Expression *expr)
+{
+	checkcodesection();
+	checksectionoverflow(4);
+	if (!rpn_isKnown(expr)) {
+		pCurrentSection->tData[nPC] = 0;
+		pCurrentSection->tData[nPC + 1] = 0;
+		pCurrentSection->tData[nPC + 2] = 0;
+		pCurrentSection->tData[nPC + 3] = 0;
+		out_CreatePatch(PATCHTYPE_LONG, expr);
+		pCurrentSection->nPC += 4;
+		nPC += 4;
+		pPCSymbol->nValue += 4;
+	} else {
+		absLong(expr->nVal);
+	}
+	rpn_Free(expr);
+}
+
+/*
+ * Output a PC-relative relocatable byte. Checking will be done to see if it
+ * is an absolute value in disguise.
+ */
+void out_PCRelByte(struct Expression *expr)
+{
+	checkcodesection();
+	checksectionoverflow(1);
+	if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) {
+		pCurrentSection->tData[nPC] = 0;
+		out_CreatePatch(PATCHTYPE_JR, expr);
+		pCurrentSection->nPC++;
+		nPC++;
+		pPCSymbol->nValue++;
+	} else {
+		/* Target is relative to the byte *after* the operand */
+		uint16_t address = pCurrentSection->nOrg + nPC + 1;
+		/* The offset wraps (jump from ROM to HRAM, for loopexample) */
+		int16_t offset = expr->nVal - address;
+
+		if (offset < -128 || offset > 127) {
+			yyerror("jr target out of reach (expected -129 < %d < 128)", offset);
+			out_AbsByte(0);
+		} else {
+			out_AbsByte(offset);
+		}
+	}
+	rpn_Free(expr);
+}
+
+/*
+ * Output a binary file
+ */
+void out_BinaryFile(char *s)
+{
+	FILE *f;
+
+	f = fstk_FindFile(s, NULL);
+	if (f == NULL) {
+		if (oGeneratedMissingIncludes) {
+			oFailedOnMissingInclude = true;
+			return;
+		}
+		err(1, "Unable to open incbin file '%s'", s);
+	}
+
+	int32_t fsize;
+
+	fseek(f, 0, SEEK_END);
+	fsize = ftell(f);
+	fseek(f, 0, SEEK_SET);
+
+	checkcodesection();
+	checksectionoverflow(fsize);
+
+	int32_t dest = nPC;
+	int32_t todo = fsize;
+
+	while (todo--)
+		pCurrentSection->tData[dest++] = fgetc(f);
+
+	pCurrentSection->nPC += fsize;
+	nPC += fsize;
+	pPCSymbol->nValue += fsize;
+	fclose(f);
+}
+
+void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length)
+{
+	FILE *f;
+
+	if (start_pos < 0)
+		fatalerror("Start position cannot be negative");
+
+	if (length < 0)
+		fatalerror("Number of bytes to read must be greater than zero");
+
+	f = fstk_FindFile(s, NULL);
+	if (f == NULL) {
+		if (oGeneratedMissingIncludes) {
+			oFailedOnMissingInclude = true;
+			return;
+		}
+		err(1, "Unable to open included file '%s'", s);
+	}
+
+	int32_t fsize;
+
+	fseek(f, 0, SEEK_END);
+	fsize = ftell(f);
+
+	if (start_pos >= fsize)
+		fatalerror("Specified start position is greater than length of file");
+
+	if ((start_pos + length) > fsize)
+		fatalerror("Specified range in INCBIN is out of bounds");
+
+	fseek(f, start_pos, SEEK_SET);
+
+	checkcodesection();
+	checksectionoverflow(length);
+
+	int32_t dest = nPC;
+	int32_t todo = length;
+
+	while (todo--)
+		pCurrentSection->tData[dest++] = fgetc(f);
+
+	pCurrentSection->nPC += length;
+	nPC += length;
+	pPCSymbol->nValue += length;
+
+	fclose(f);
+}
+
+/*
+ * Section stack routines
+ */
+void out_PushSection(void)
+{
+	struct SectionStackEntry *pSect;
+
+	pSect = malloc(sizeof(struct SectionStackEntry));
+	if (pSect == NULL)
+		fatalerror("No memory for section stack");
+
+	pSect->pSection = pCurrentSection;
+	pSect->pScope = sym_GetCurrentSymbolScope();
+	pSect->pNext = pSectionStack;
+	pSectionStack = pSect;
+}
+
+void out_PopSection(void)
+{
+	if (pSectionStack == NULL)
+		fatalerror("No entries in the section stack");
+
+	struct SectionStackEntry *pSect;
+
+	pSect = pSectionStack;
+	setCurrentSection(pSect->pSection);
+	sym_SetCurrentSymbolScope(pSect->pScope);
+	pSectionStack = pSect->pNext;
+	free(pSect);
+}
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -21,7 +21,7 @@
 #include "asm/symbol.h"
 #include "asm/main.h"
 #include "asm/mymath.h"
-#include "asm/output.h"
+#include "asm/section.h"
 #include "asm/util.h"
 #include "asm/warning.h"