Browse Source

Mlink-format relocs.

git-svn-id: file:///var/svn/tigccpp/trunk/tigcc/ld-tigcc@161 9552661e-59e3-4036-b4f2-dbe53926924f
kevinkofler 19 years ago
parent
commit
ee6447ce15
4 changed files with 280 additions and 3 deletions
  1. 244 1
      insert/comprrlc.c
  2. 21 1
      insert/comprrlc.h
  3. 11 0
      special.c
  4. 4 1
      special.h

+ 244 - 1
insert/comprrlc.c

@@ -152,7 +152,7 @@ Continue:
 }
 
 // Emit a compressed reloc given the true offset between the 2 relocs. Compute
-// the offset as used in the compressed reloc table or gives an error message if
+// the offset as used in the compressed reloc table or give an error message if
 // it isn't representable. Call EmitCompressedReloc with the computed offset.
 // Return TRUE on success, FALSE on failure.
 static BOOLEAN EmitCompressedRelocFromActualOffset (SECTION *Section, OFFSET Offset)
@@ -894,3 +894,246 @@ Fargo021LibsOutOfMem:
 }
 
 #endif /* FARGO_SUPPORT */
+
+
+// Emit an mlink-format compressed reloc. If Offset is -1, end the relocation
+// table. Return TRUE on success, FALSE on failure.
+static BOOLEAN EmitMlinkReloc (SECTION *Section, OFFSET Offset)
+{
+#define AppendI1(i1) ({if (!AppendI1ToSection (Section, (i1))) return FALSE;})
+#define AppendI2(i2) ({if (!AppendI2ToSection (Section, (i2))) return FALSE;})
+	
+	if (Offset == -1)
+	{
+		// End the relocation table.
+		AppendI1(0);
+	}
+	else
+	{
+		if (Offset < 128)
+		{
+			// We have 1 byte.
+			AppendI1 (Offset + 0x80);
+		}
+		else if (Offset < 16384)
+		{
+			// We have 2 bytes.
+			AppendI1 (Offset >> 7);
+			AppendI1 ((Offset & 0x7F) + 0x80);
+		}
+		else if (Offset < 2097152)
+		{
+			// We have 3 bytes.
+			AppendI1 (Offset >> 14);
+			AppendI1 ((Offset >> 7) & 0x7F);
+			AppendI1 ((Offset & 0x7F) + 0x80);
+		}
+		else
+			Error (Section->FileName, "Offset `%ld' for mlink-format reloc doesn't fit into 3 bytes.", (long) Offset);
+	}
+	
+#undef AppendI1
+#undef AppendI2
+	
+	return TRUE;
+}
+
+// Emit an mlink-format compressed reloc given the true offset between the 2
+// relocs. Compute the offset as used in the compressed reloc table or give
+// an error message if
+// it isn't representable. Call EmitCompressedReloc with the computed offset.
+// Return TRUE on success, FALSE on failure.
+static BOOLEAN EmitMlinkRelocFromActualOffset (SECTION *Section, OFFSET Offset)
+{
+	if ((Offset > 0) && (Offset & 1))
+	{
+		Error (Section->FileName, "Odd offset `%ld' between 2 absolute relocs. Even offset needed.", (long) Offset);
+		return FALSE;
+	}
+
+	if (Offset < 0)
+	{
+		Error (Section->FileName, "Invalid internal reloc sorting order (offset `-0x%lx', need positive offset).",
+		       -Offset);
+		return FALSE;
+	}
+	
+	return EmitMlinkReloc (Section, Offset >> 1);
+}
+
+// Emit a reloc table in mlink compressed format for the items enumerated in the
+// list model specified by Model.
+static BOOLEAN EmitMlinkFormatRelocs (LIST_MODEL *Model, SECTION *SourceSection, const LOCATION *SourceBase, void *UserData, SECTION *Section)
+{
+	if (!SourceSection)
+		SourceSection = Section;
+	
+	SourceSection->Frozen = TRUE;
+	
+	{
+		void *NextItem = NULL;
+		OFFSET Offset;
+		
+		// Output the first item in the list...
+		// Output the target offset, and get the reloc's location.
+		Offset = Model (SourceSection, &NextItem, UserData, FALSE, TRUE);
+		
+		// A return value < 0 indicates that the list was empty.
+		if (Offset >= 0)
+		{
+			OFFSET BaseAddress = GetLocationOffset (SourceSection, SourceBase);
+			
+			if (BaseAddress & 1)
+			{
+				Error (Section->FileName, "Invalid base address `0x%lx'. Even base address needed.", BaseAddress);
+				return FALSE;
+			}
+			
+			if (Offset & 1)
+			{
+				Error (Section->FileName, "Odd offset between base address `0x%lx' and first absolute reloc `0x%lx'. Even offset needed.", BaseAddress, Offset);
+				return FALSE;
+			}
+			
+			if (Offset < BaseAddress)
+			{
+				Error (Section->FileName, "Cannot emit absolute reloc located at `0x%lx' before base address.", Offset);
+				return FALSE;
+			}
+			
+			// Emit the reloc.
+			if (!(EmitCompressedReloc (Section, (Offset - BaseAddress) >> 1)))
+				return FALSE;
+			
+	 		// Output the remaining items in the list...
+			while (NextItem)
+			{
+				// Save the previous offset.
+				OFFSET LastOffset = Offset;
+				
+				// Output the target offset, and get the reloc's location.
+				Offset = Model (SourceSection, &NextItem, UserData, FALSE, TRUE);
+				
+				// A negative offset means the list ends here.
+				if (Offset >= 0)
+				{
+					// Emit the reloc.
+					if (!(EmitMlinkRelocFromActualOffset (Section, Offset - LastOffset)))
+						return FALSE;
+				}
+			}
+		}
+		
+		return EmitMlinkReloc (Section, -1);
+	}
+}
+
+// Append mlink-style relocation entries in the format required by the TIGCCLIB
+// relocation code. If TargetSection is NULL, append all relocation entries that
+// point to unhandled sections. Otherwise, append all relocation entries
+// pointing to this section.
+// Warning: Inserting relocs is special: Since the relocs are changed
+// during the process, they can be inserted only once.
+BOOLEAN InsertMlinkRelocs (SECTION *Section, SECTION *TargetSection, SECTION *MergedSection, const LOCATION *Reference)
+{
+	// Initialize user data for list model.
+	RELOC_USER_DATA UserData = {TargetSection};
+	
+	// If a target section is specified, it is essential now, and it may
+	// not be modified any more.
+	if (TargetSection)
+		TargetSection->Frozen = TargetSection->Essential = TRUE;
+	else
+		// Do code optimizations now, since this might reduce the number
+		// of relocs. If a target section was specified, this is pointless,
+		// as relocs into a separate section can never be optimized away.
+		FixCode (Section->Parent);
+	
+	// Apply the format documented in _mlink_format_relocs.s.
+	if (!(EmitMlinkFormatRelocs ((LIST_MODEL *) RelocListModel, MergedSection, Reference, &UserData, Section)))
+		return FALSE;
+	
+	// If a target section was specified, and its Handled flag was not
+	// set yet, now setting it is probably correct.
+	if (TargetSection)
+		TargetSection->Handled = TRUE;
+	
+	return TRUE;
+}
+
+// Append mlink-style relocation entries in the format required by the TIGCCLIB
+// relocation code, using InsertCompressedRelocs. If TargetSection is NULL,
+// output an empty relocation table. Otherwise, append all relocation entries
+// pointing to this section.
+// Warning: Inserting relocs is special: Since the relocs are changed
+// during the process, they can be inserted only once.
+BOOLEAN InsertMlinkSectionRefs (SECTION *Section, SECTION *TargetSection, SECTION *MergedSection, const LOCATION *Reference)
+{
+	if (TargetSection)
+		return InsertMlinkRelocs (Section, TargetSection, MergedSection, Reference);
+	else
+		return (AllocateSpaceInSection (Section, 1) != NULL);
+}
+
+// Append ROM calls in the mlink-style format required by the TIGCCLIB
+// relocation code.
+BOOLEAN InsertMlinkROMCalls (SECTION *Section, SECTION *MergedSection, const LOCATION *Reference)
+{
+	PROGRAM *Program = Section->Parent;
+	
+	// Initialize user data for list model.
+	ROM_CALL_USER_DATA UserData = {NULL, 0, -1};
+	
+	// Allocate space for dynamic user data.
+	if (!(UserData.ROMFunctions = calloc (Program->HighestROMCall + 1, sizeof (ROM_CALL_FUNCTION_DATA))))
+	{
+		Error (NULL, "Out of memory while inserting ROM calls with mlink-format relocs.");
+		return FALSE;
+	}
+	
+	{
+		BOOLEAN Result = TRUE;
+		
+		// Go through all ROM calls and increment the appropriate counters.
+		COUNT ROMRelocCount = GetSectionItemCount ((LIST_MODEL *) ROMCallListModel, MergedSection ? : Section, &UserData);
+		
+		// If no ROM calls are used, do not output anything but the final null-terminator.
+		if (ROMRelocCount > 0)
+		{
+			// Apply the format documented in _compressed_format_rom_calls.s.
+			OFFSET LastFunction = -1;
+			
+			for (UserData.CurFunction = 0; UserData.CurFunction <= Program->HighestROMCall; UserData.CurFunction++)
+			{
+				if (UserData.ROMFunctions[UserData.CurFunction].RelocCount)
+				{
+					// Emit the function number as a compressed offset.
+					OFFSET FunctionOffset = UserData.CurFunction - LastFunction;
+					if (!(EmitMlinkReloc (Section, FunctionOffset)))
+					{
+						Result = FALSE;
+						break;
+					}
+					LastFunction = UserData.CurFunction;
+						
+					// Emit all ROM calls using this function.
+					if (!(EmitMlinkFormatRelocs ((LIST_MODEL *) ROMCallListModel, MergedSection, Reference, &UserData, Section)))
+					{
+						Result = FALSE;
+						break;
+					}
+				}
+			}
+		}
+		
+		// Output the final null-terminator.
+		if (!(AppendI1ToSection (Section, 0)))
+			Result = FALSE;
+		
+		// Free the extra information.
+		free (UserData.ROMFunctions);
+		
+		return Result;
+	}
+}
+

+ 21 - 1
insert/comprrlc.h

@@ -1,6 +1,6 @@
 /* comprrlc.h: Routines for compressed relocation tables
 
-   Copyright (C) 2003 Kevin Kofler
+   Copyright (C) 2003-2005 Kevin Kofler
    Portions copyright (C) 2002-2003 Sebastian Reichelt
 
    This program is free software; you can redistribute it and/or modify
@@ -77,4 +77,24 @@ BOOLEAN InsertFargo021SectionRefs (SECTION *Section, SECTION *TargetSection, SEC
 BOOLEAN InsertFargo021Libraries (SECTION *Section, SECTION *MergedSection, const LOCATION *Reference);
 #endif /* FARGO_SUPPORT */
 
+// Append mlink-style relocation entries in the format required by the TIGCCLIB
+// relocation code. If TargetSection is NULL, append all relocation entries that
+// point to unhandled sections. Otherwise, append all relocation entries
+// pointing to this section.
+// Warning: Inserting relocs is special: Since the relocs are changed
+// during the process, they can be inserted only once.
+BOOLEAN InsertMlinkRelocs (SECTION *Section, SECTION *TargetSection, SECTION *MergedSection, const LOCATION *Reference);
+
+// Append mlink-style relocation entries in the format required by the TIGCCLIB
+// relocation code, using InsertCompressedRelocs. If TargetSection is NULL,
+// output an empty relocation table. Otherwise, append all relocation entries
+// pointing to this section.
+// Warning: Inserting relocs is special: Since the relocs are changed
+// during the process, they can be inserted only once.
+BOOLEAN InsertMlinkSectionRefs (SECTION *Section, SECTION *TargetSection, SECTION *MergedSection, const LOCATION *Reference);
+
+// Append ROM calls in the mlink-style format required by the TIGCCLIB
+// relocation code.
+BOOLEAN InsertMlinkROMCalls (SECTION *Section, SECTION *MergedSection, const LOCATION *Reference);
+
 #endif

+ 11 - 0
special.c

@@ -1216,6 +1216,7 @@ SYMBOL *HandleAutoInsertion (SECTION *Section, const char *SymbolName)
 		
 		// All insertions except compressed ones should be aligned on a 2-byte boundary.
 		if ((!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT_COMPRESSED, sizeof (SYMPF_BUILTIN_INSERT_COMPRESSED) - 1)))
+		 || (!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT_MLINK, sizeof (SYMPF_BUILTIN_INSERT_MLINK) - 1)))
 		 || (!(strcmp (SymbolName, SYMPF_BUILTIN_INSERT "fargo021_relocs")))
 		 || (!(strcmp (SymbolName, SYMPF_BUILTIN_INSERT "preos_compressed_tables")))
 		 || PadSection (Section, 2))
@@ -1353,6 +1354,16 @@ BOOLEAN AppendInsertionData (SECTION *Section, const char *Name, SECTION *Merged
 				else if (NameMatches ("compressed_rom_calls"))
 					return InsertCompressedROMCalls (Section, MergedSection, &Reference);
 				
+				// Compressed relocation tables using our own mlink-style format.
+				else if (NameMatches ("mlink_relocs"))
+					return InsertMlinkRelocs (Section, NULL, MergedSection, &Reference);
+				else if (NameMatches ("mlink_bss_refs"))
+					return InsertMlinkSectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
+				else if (NameMatches ("mlink_data_refs"))
+					return InsertMlinkSectionRefs (Section, Program->DataSection, MergedSection, &Reference);
+				else if (NameMatches ("mlink_rom_calls"))
+					return InsertMlinkROMCalls (Section, MergedSection, &Reference);
+				
 				else
 					Warning (GetFileName (Section, Section->Size), "Unrecognized insertion `%s'.", Name);
 			}

+ 4 - 1
special.h

@@ -1,7 +1,7 @@
 /* special.h: Routines to handle special characteristics of the linker
 
    Copyright (C) 2002-2003 Sebastian Reichelt
-   Copyright (C) 2003 Kevin Kofler
+   Copyright (C) 2003-2005 Kevin Kofler
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -42,6 +42,9 @@
 #define SYMPF_COMPRESSED "compressed_"
 #define SYMPF_BUILTIN_INSERT_COMPRESSED SYMPF_BUILTIN_INSERT SYMPF_COMPRESSED
 
+#define SYMPF_MLINK "mlink_"
+#define SYMPF_BUILTIN_INSERT_MLINK SYMPF_BUILTIN_INSERT SYMPF_MLINK
+
 #define SYMPF_CALC_CONST "calc_const_"
 #define SYMPF_BUILTIN_CALC_CONST SYMPF_BUILTIN SYMPF_CALC_CONST