123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- /* exp_tios.c: Routines to export to a TIOS file
- Copyright (C) 2002-2003 Sebastian Reichelt
- 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
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
- #include "exp_tios.h"
- #ifdef TIOS_SUPPORT
- #include <string.h>
- #include "../manip.h"
- #include "../special.h"
- #include "../formats/tios.h"
- // Get the file size needed to export the program into a TIOS file.
- // Returns 0 on failure.
- // Call this function once to receive necessary error messages.
- SIZE GetTIOSFileSize (const PROGRAM *Program)
- {
- // Get a pointer to the main section.
- SECTION *MainSection = Program->MainSection;
-
- if (!MainSection)
- {
- Error (NULL, "No main section.");
- return 0;
- }
-
- {
- // Start with the size of the section.
- // Add 2 for the two null bytes at the beginning of the reloc table.
- SIZE Size = MainSection->Size + 2;
-
- if (!(IsEmpty (MainSection->Relocs)))
- {
- RELOC *Reloc;
-
- // Add the size needed for the relocs.
- for_each (Reloc, MainSection->Relocs)
- {
- // If this can be resolved to a calculator-dependent value, ignore the
- // reloc for now.
- if (IsPlainCalcBuiltin (Reloc))
- continue;
-
- // We can only emit 4-byte absolute relocs.
- if (Reloc->Relative || (Reloc->Size != 4))
- {
- Error (GetFileName (MainSection, Reloc->Location), "Cannot emit %ld byte %s reloc to `%s'.", (long) Reloc->Size, Reloc->Relative ? "relative" : "absolute", Reloc->Target.SymbolName);
- Size = 0;
- }
-
- if (Size)
- // A reloc takes 4 bytes: 2 bytes for the location and 2 bytes for the target offset.
- Size += 4;
- }
- }
-
- return Size;
- }
- }
- // Export the internal data structures into a TIOS file.
- BOOLEAN ExportTIOSFile (const PROGRAM *Program, EXP_FILE *File, SIZE FileSize, ProgramCalcs DestCalc)
- {
- // A simple macro to make the code more readable.
- #define FailWithError(Err...) ({ Error (Err); return FALSE; })
-
- const char *SectionFileName = NULL;
- OFFSET DataStart = 0;
-
- COUNT EmittedRelocCount = 0;
-
- // Get a pointer to the main section.
- SECTION *MainSection = Program->MainSection;
-
- if (!MainSection)
- FailWithError (NULL, "No main section.");
-
- SectionFileName = MainSection->FileName;
-
- // In nostub mode, execution simply starts at the beginning of
- // the first section. But ideally, startup code should always be
- // marked as such. When merging sections, the destination startup
- // number is kept, so in the end, the complete code is marked as
- // a startup section (which makes sense; it is startable).
- if (!(MainSection->StartupNumber || (Program->Type == PT_NOSTUB)))
- FailWithError (SectionFileName, "No startup section(s) defined.");
-
- if (!(MainSection->Data))
- FailWithError (SectionFileName, "No section contents.");
-
- // Write out the section contents first.
- DataStart = ExportTell (File);
- ExportWrite (File, MainSection->Data, MainSection->Size, 1);
-
- // Write out two zero bytes as a separator.
- ExportWriteTI2 (File, 0);
-
- if (!(IsEmpty (MainSection->Relocs)))
- {
- RELOC *Reloc;
-
- // Write out the relocation table.
- for (Reloc = GetLast (MainSection->Relocs); Reloc; Reloc = GetPrev (Reloc))
- {
- // Get the current file name for error messages.
- const char *CurFileName = GetFileName (MainSection, Reloc->Location);
-
- // If this can be resolved to a calculator-dependent value, write the
- // value into the section data.
- if (EmitCalcBuiltinValue (Reloc, DestCalc, File, FileSize, DataStart))
- continue;
-
- // We can only emit relocs with a target symbol in the same section.
- if (!(Reloc->Target.Symbol))
- FailWithError (CurFileName, "Unresolved reference to `%s'.", Reloc->Target.SymbolName);
- if (Reloc->Target.Symbol->Parent != MainSection)
- FailWithError (CurFileName, "Cannot emit reloc to `%s' in different section.", Reloc->Target.SymbolName);
-
- // We can only emit 4-byte absolute relocs.
- if (Reloc->Relative || (Reloc->Size != 4))
- FailWithError (CurFileName, "Cannot emit %ld byte %s reloc to `%s'.", (long) Reloc->Size, Reloc->Relative ? "relative" : "absolute", Reloc->Target.SymbolName);
-
- if (((I2) Reloc->Location) != Reloc->Location)
- FailWithError (CurFileName, "Cannot emit reloc outside of limited program range to `%s'.", Reloc->Target.SymbolName);
-
- {
- OFFSET TargetLocation = GetLocationOffset (MainSection, &(Reloc->Target)) + Reloc->FixedOffset;
-
- if (((I2) TargetLocation) != TargetLocation)
- FailWithError (CurFileName, "Cannot emit reloc to `%s' (Offset %ld; Location 0x%lX) outside of limited program range.", Reloc->Target.SymbolName, (long) (Reloc->Target.Offset + Reloc->FixedOffset), (long) (TargetLocation));
-
- // Everything seems to be correct.
- ExportWriteTI2 (File, TargetLocation);
- ExportWriteTI2 (File, Reloc->Location);
-
- // Increase the statistics.
- EmittedRelocCount++;
- }
- }
- }
-
- if ((!(IsEmpty (MainSection->ROMCalls))) && (!(MainSection->ROMCalls.Handled)))
- FailWithError (SectionFileName, "ROM calls are not supported in this mode.");
-
- if ((!(IsEmpty (MainSection->RAMCalls))) && (!(MainSection->RAMCalls.Handled)))
- FailWithError (SectionFileName, "RAM calls are not supported in this mode.");
-
- if ((!(IsEmpty (MainSection->LibCalls))) && (!(MainSection->LibCalls.Handled)))
- FailWithError (SectionFileName, "Library calls are not supported in this mode.");
-
- if (Program->OptimizeInfo->NativeRelocCount < EmittedRelocCount)
- Program->OptimizeInfo->NativeRelocCount = EmittedRelocCount;
-
- return TRUE;
-
- #undef FailWithError
- }
- #ifdef PUCRUNCH_SUPPORT
- #include "pucrunch.h"
- // Export the internal data structures into a packed TIOS file.
- BOOLEAN ExportPackedTIOSFile (const PROGRAM *Program, EXP_FILE *File, SIZE FileSize, ProgramCalcs DestCalc)
- {
- // Some macros to make the code more readable.
- #define FailWithError(Err...) ({ Error (Err); return FALSE; })
- #define BufferWrite(P,L,C) (memcpy (Buffer + CurPos, P, (L) * (C)), CurPos += (L) * (C))
- #define BufferWriteTI2(D) ({ WriteTI2 (*((TI2 *) (Buffer + CurPos)), D); CurPos += 2; })
-
- const char *SectionFileName = NULL;
- OFFSET DataStart = 0;
-
- COUNT EmittedRelocCount = 0;
-
- // Calculate the size needed for the two size bytes and the
- // tag.
- SIZE VarFileSize = 2 + FileSize + 1;
- I1 Buffer[VarFileSize];
- OFFSET CurPos = 0;
-
- // Write out the 2 size bytes.
- BufferWriteTI2 (VarFileSize - 2);
-
- // Get a pointer to the main section.
- SECTION *MainSection = Program->MainSection;
-
- if (!MainSection)
- FailWithError (NULL, "No main section.");
-
- SectionFileName = MainSection->FileName;
-
- // In nostub mode, execution simply starts at the beginning of
- // the first section. But ideally, startup code should always be
- // marked as such. When merging sections, the destination startup
- // number is kept, so in the end, the complete code is marked as
- // a startup section (which makes sense; it is startable).
- if (!(MainSection->StartupNumber || (Program->Type == PT_NOSTUB)))
- FailWithError (SectionFileName, "No startup section(s) defined.");
-
- if (!(MainSection->Data))
- FailWithError (SectionFileName, "No section contents.");
-
- // Write out the section contents first.
- DataStart = CurPos;
- BufferWrite (MainSection->Data, MainSection->Size, 1);
-
- // Write out two zero bytes as a separator.
- BufferWriteTI2 (0);
-
- if (!(IsEmpty (MainSection->Relocs)))
- {
- RELOC *Reloc;
-
- // Write out the relocation table.
- for (Reloc = GetLast (MainSection->Relocs); Reloc; Reloc = GetPrev (Reloc))
- {
- // Get the current file name for error messages.
- const char *CurFileName = GetFileName (MainSection, Reloc->Location);
-
- // If this can be resolved to a calculator-dependent value, write the
- // value into the section data.
- if (EmitCalcBuiltinValueBuf (Reloc, DestCalc, Buffer, FileSize, DataStart))
- continue;
-
- // We can only emit relocs with a target symbol in the same section.
- if (!(Reloc->Target.Symbol))
- FailWithError (CurFileName, "Unresolved reference to `%s'.", Reloc->Target.SymbolName);
- if (Reloc->Target.Symbol->Parent != MainSection)
- FailWithError (CurFileName, "Cannot emit reloc to `%s' in different section.", Reloc->Target.SymbolName);
-
- // We can only emit 4-byte absolute relocs.
- if (Reloc->Relative || (Reloc->Size != 4))
- FailWithError (CurFileName, "Cannot emit %ld byte %s reloc to `%s'.", (long) Reloc->Size, Reloc->Relative ? "relative" : "absolute", Reloc->Target.SymbolName);
-
- if (((I2) Reloc->Location) != Reloc->Location)
- FailWithError (CurFileName, "Cannot emit reloc outside of limited program range to `%s'.", Reloc->Target.SymbolName);
-
- {
- OFFSET TargetLocation = GetLocationOffset (MainSection, &(Reloc->Target)) + Reloc->FixedOffset;
-
- if (((I2) TargetLocation) != TargetLocation)
- FailWithError (CurFileName, "Cannot emit reloc to `%s' (Offset %ld; Location 0x%lX) outside of limited program range.", Reloc->Target.SymbolName, (long) (Reloc->Target.Offset + Reloc->FixedOffset), (long) (TargetLocation));
-
- // Everything seems to be correct.
- BufferWriteTI2 (TargetLocation);
- BufferWriteTI2 (Reloc->Location);
-
- // Increase the statistics.
- EmittedRelocCount++;
- }
- }
- }
-
- if ((!(IsEmpty (MainSection->ROMCalls))) && (!(MainSection->ROMCalls.Handled)))
- FailWithError (SectionFileName, "ROM calls are not supported in this mode.");
-
- if ((!(IsEmpty (MainSection->RAMCalls))) && (!(MainSection->RAMCalls.Handled)))
- FailWithError (SectionFileName, "RAM calls are not supported in this mode.");
-
- if ((!(IsEmpty (MainSection->LibCalls))) && (!(MainSection->LibCalls.Handled)))
- FailWithError (SectionFileName, "Library calls are not supported in this mode.");
-
- // Write out the final ASM tag.
- Buffer[CurPos] = TIOS_TAG_ASM;
-
- if (Program->OptimizeInfo->NativeRelocCount < EmittedRelocCount)
- Program->OptimizeInfo->NativeRelocCount = EmittedRelocCount;
-
- // Now compress the buffer and write it out to the file.
- return !TTPack(0, VarFileSize, Buffer, File);
-
- #undef FailWithError
- }
- #endif /* PUCRUNCH_SUPPORT */
- #endif /* TIOS_SUPPORT */
|