forked from KolibriOS/kolibrios
Added objconv port.
git-svn-id: svn://kolibrios.org@9683 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
718
programs/develop/objconv/containers.cpp
Normal file
718
programs/develop/objconv/containers.cpp
Normal file
@@ -0,0 +1,718 @@
|
||||
/**************************** containers.cpp **********************************
|
||||
* Author: Agner Fog
|
||||
* Date created: 2006-07-15
|
||||
* Last modified: 2016-07-07
|
||||
* Project: objconv
|
||||
* Module: containers.cpp
|
||||
* Description:
|
||||
* Objconv is a portable C++ program for converting object file formats.
|
||||
* Compile for console mode on any platform.
|
||||
*
|
||||
* This module contains container classes CMemoryBuffer and CFileBuffer for
|
||||
* dynamic memory allocation and file read/write. See containers.h for
|
||||
* further description.
|
||||
*
|
||||
* Copyright 2006-2016 GNU General Public License http://www.gnu.org/licenses
|
||||
*****************************************************************************/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// Names of file formats
|
||||
SIntTxt FileFormatNames[] = {
|
||||
{FILETYPE_COFF, "COFF"},
|
||||
{FILETYPE_OMF, "OMF"},
|
||||
{FILETYPE_ELF, "ELF"},
|
||||
{FILETYPE_MACHO_LE, "Mach-O Little Endian"},
|
||||
{FILETYPE_MACHO_BE, "Mach-O Big Endian"},
|
||||
{FILETYPE_DOS, "DOS executable"},
|
||||
{FILETYPE_WIN3X, "Windows 3.x executable"},
|
||||
{FILETYPE_LIBRARY, "Function library"},
|
||||
{FILETYPE_OMFLIBRARY, "Function library (OMF)"},
|
||||
{IMPORT_LIBRARY_MEMBER, "Windows import library member"},
|
||||
{FILETYPE_MAC_UNIVBIN, "MacIntosh universal binary"},
|
||||
{FILETYPE_MS_WPO, "Whole program optimization intermediate file, Microsoft specific"},
|
||||
{FILETYPE_INTEL_WPO, "Whole program optimization intermediate file, Intel specific"},
|
||||
{FILETYPE_WIN_UNKNOWN, "Unknown subtype, Windows"},
|
||||
{FILETYPE_ASM, "Disassembly"}
|
||||
};
|
||||
|
||||
|
||||
// Members of class CMemoryBuffer
|
||||
CMemoryBuffer::CMemoryBuffer() {
|
||||
// Constructor
|
||||
buffer = 0;
|
||||
NumEntries = DataSize = BufferSize = 0;
|
||||
}
|
||||
|
||||
CMemoryBuffer::~CMemoryBuffer() {
|
||||
// Destructor
|
||||
SetSize(0); // De-allocate buffer
|
||||
}
|
||||
|
||||
void CMemoryBuffer::SetSize(uint32 size) {
|
||||
// Allocate, reallocate or deallocate buffer of specified size.
|
||||
// DataSize is initially zero. It is increased by Push or PushString.
|
||||
// Setting size > DataSize will allocate more buffer and fill it with zeroes but not increase DataSize.
|
||||
// Setting size < DataSize will decrease DataSize so that some of the data are discarded.
|
||||
// Setting size = 0 will discard all data and de-allocate the buffer.
|
||||
if (size == 0) {
|
||||
// Deallocate
|
||||
if (buffer) delete[] buffer; // De-allocate buffer
|
||||
buffer = 0;
|
||||
NumEntries = DataSize = BufferSize = 0;
|
||||
return;
|
||||
}
|
||||
if (size < DataSize) {
|
||||
// Request to delete some data
|
||||
DataSize = size;
|
||||
return;
|
||||
}
|
||||
if (size <= BufferSize) {
|
||||
// Request to reduce size but not delete it
|
||||
return; // Ignore
|
||||
}
|
||||
// size = (size + 15) & uint32(-16); // Round up size to value divisible by 16
|
||||
size = (size + BufferSize + 15) & uint32(-16); // Double size and round up to value divisible by 16
|
||||
int8 * buffer2 = 0; // New buffer
|
||||
buffer2 = new int8[size]; // Allocate new buffer
|
||||
if (buffer2 == 0) {err.submit(9006); return;} // Error can't allocate
|
||||
memset (buffer2, 0, size); // Initialize to all zeroes
|
||||
if (buffer) {
|
||||
// A smaller buffer is previously allocated
|
||||
memcpy (buffer2, buffer, BufferSize); // Copy contents of old buffer into new
|
||||
delete[] buffer; // De-allocate old buffer
|
||||
}
|
||||
buffer = buffer2; // Save pointer to buffer
|
||||
BufferSize = size; // Save size
|
||||
}
|
||||
|
||||
uint32 CMemoryBuffer::Push(void const * obj, uint32 size) {
|
||||
// Add object to buffer, return offset
|
||||
// Parameters:
|
||||
// obj = pointer to object, 0 if fill with zeroes
|
||||
// size = size of object to push
|
||||
|
||||
// Old offset will be offset to new object
|
||||
uint32 OldOffset = DataSize;
|
||||
|
||||
// New data size will be old data size plus size of new object
|
||||
uint32 NewOffset = DataSize + size;
|
||||
|
||||
if (NewOffset > BufferSize) {
|
||||
// Buffer too small, allocate more space.
|
||||
// We can use SetSize for this only if it is certain that obj is not
|
||||
// pointing to an object previously allocated in the old buffer
|
||||
// because it would be deallocated before copied into the new buffer:
|
||||
// SetSize (NewOffset + NewOffset / 2 + 1024);
|
||||
|
||||
// Allocate more space without using SetSize:
|
||||
// Double the size + 1 kB, and round up size to value divisible by 16
|
||||
uint32 NewSize = (NewOffset * 2 + 1024 + 15) & uint32(-16);
|
||||
int8 * buffer2 = 0; // New buffer
|
||||
// Allocate new buffer
|
||||
buffer2 = new int8[NewSize];
|
||||
if (buffer2 == 0) {
|
||||
// Error can't allocate
|
||||
err.submit(9006); return 0;
|
||||
}
|
||||
// Initialize to all zeroes
|
||||
memset (buffer2, 0, NewSize);
|
||||
if (buffer) {
|
||||
// A smaller buffer is previously allocated
|
||||
// Copy contents of old buffer into new
|
||||
memcpy (buffer2, buffer, BufferSize);
|
||||
}
|
||||
BufferSize = NewSize; // Save size
|
||||
if (obj && size) {
|
||||
// Copy object to new buffer
|
||||
memcpy (buffer2 + OldOffset, obj, size);
|
||||
obj = 0; // Prevent copying once more
|
||||
}
|
||||
// Delete old buffer after copying object
|
||||
if (buffer) delete[] buffer;
|
||||
|
||||
// Save pointer to new buffer
|
||||
buffer = buffer2;
|
||||
}
|
||||
// Copy object to buffer if nonzero
|
||||
if (obj && size) {
|
||||
memcpy (buffer + OldOffset, obj, size);
|
||||
}
|
||||
if (size) {
|
||||
// Adjust new offset
|
||||
DataSize = NewOffset;
|
||||
NumEntries++;
|
||||
}
|
||||
// Return offset to allocated object
|
||||
return OldOffset;
|
||||
}
|
||||
|
||||
uint32 CMemoryBuffer::PushString(char const * s) {
|
||||
// Add ASCIIZ string to buffer, return offset
|
||||
return Push (s, uint32(strlen(s))+1);
|
||||
}
|
||||
|
||||
uint32 CMemoryBuffer::GetLastIndex() {
|
||||
// Index of last object pushed (zero-based)
|
||||
return NumEntries - 1;
|
||||
}
|
||||
|
||||
void CMemoryBuffer::SetDataSize(uint32 size) {
|
||||
if (size > BufferSize) {
|
||||
// Allocate more space
|
||||
SetSize(size + 2048);
|
||||
}
|
||||
// Set DataSize to after alignment space
|
||||
DataSize = size;
|
||||
}
|
||||
|
||||
void CMemoryBuffer::Align(uint32 a) {
|
||||
// Align next entry to address divisible by a
|
||||
SetDataSize((DataSize + a - 1) / a * a);
|
||||
}
|
||||
|
||||
// Members of class CFileBuffer
|
||||
CFileBuffer::CFileBuffer() : CMemoryBuffer() {
|
||||
// Default constructor
|
||||
FileName = 0;
|
||||
OutputFileName = 0;
|
||||
FileType = WordSize = Executable = 0;
|
||||
}
|
||||
|
||||
CFileBuffer::CFileBuffer(char const * filename) : CMemoryBuffer() {
|
||||
// Constructor
|
||||
FileName = filename;
|
||||
FileType = WordSize = 0;
|
||||
}
|
||||
|
||||
void CFileBuffer::Read(int IgnoreError) {
|
||||
// Read file into buffer
|
||||
uint32 status; // Error status
|
||||
|
||||
#ifdef _MSC_VER // Microsoft compiler prefers this:
|
||||
|
||||
int fh; // File handle
|
||||
fh = _open(FileName, O_RDONLY | O_BINARY); // Open file in binary mode
|
||||
if (fh == -1) {
|
||||
// Cannot read file
|
||||
if (!IgnoreError) err.submit(2103, FileName); // Error. Input file must be read
|
||||
SetSize(0); return; // Make empty file buffer
|
||||
}
|
||||
DataSize = filelength(fh); // Get file size
|
||||
if (DataSize <= 0) {
|
||||
if (!IgnoreError) err.submit(2105, FileName); // Wrong size
|
||||
return;}
|
||||
SetSize(DataSize + 2048); // Allocate buffer, 2k extra
|
||||
status = _read(fh, Buf(), DataSize); // Read from file
|
||||
if (status != DataSize) err.submit(2103, FileName);
|
||||
status = _close(fh); // Close file
|
||||
if (status != 0) err.submit(2103, FileName);
|
||||
|
||||
#else // Works with most compilers:
|
||||
|
||||
FILE * fh = fopen(FileName, "rb");
|
||||
if (!fh) {
|
||||
// Cannot read file
|
||||
if (!IgnoreError) err.submit(2103, FileName); // Error. Input file must be read
|
||||
SetSize(0); return; // Make empty file buffer
|
||||
}
|
||||
// Find file size
|
||||
fseek(fh, 0, SEEK_END);
|
||||
long int fsize = ftell(fh);
|
||||
if (fsize <= 0 || (unsigned long)fsize >= 0xFFFFFFFF) {
|
||||
// File too big or zero size
|
||||
err.submit(2105, FileName); fclose(fh); return;
|
||||
}
|
||||
DataSize = (uint32)fsize;
|
||||
rewind(fh);
|
||||
// Allocate buffer
|
||||
SetSize(DataSize + 2048); // Allocate buffer, 2k extra
|
||||
// Read entire file
|
||||
status = (uint32)fread(Buf(), 1, DataSize, fh);
|
||||
if (status != DataSize) err.submit(2103, FileName);
|
||||
status = fclose(fh);
|
||||
if (status != 0) err.submit(2103, FileName);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void CFileBuffer::Write() {
|
||||
// Write buffer to file:
|
||||
if (OutputFileName) FileName = OutputFileName;
|
||||
// Two alternative ways to write a file:
|
||||
|
||||
#ifdef _MSC_VER // Microsoft compiler prefers this:
|
||||
|
||||
int fh; // File handle
|
||||
uint32 status; // Error status
|
||||
// Open file in binary mode
|
||||
fh = _open(FileName, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, _S_IREAD | _S_IWRITE);
|
||||
// Check if error
|
||||
if (fh == -1) {err.submit(2104, FileName); return;}
|
||||
// Write file
|
||||
status = _write(fh, Buf(), DataSize);
|
||||
// Check if error
|
||||
if (status != DataSize) err.submit(2104, FileName);
|
||||
// Close file
|
||||
status = _close(fh);
|
||||
// Check if error
|
||||
if (status != 0) err.submit(2104, FileName);
|
||||
|
||||
#else // Works with most compilers:
|
||||
|
||||
// Open file in binary mode
|
||||
FILE * ff = fopen(FileName, "wb");
|
||||
// Check if error
|
||||
if (!ff) {err.submit(2104, FileName); return;}
|
||||
// Write file
|
||||
uint32 n = (uint32)fwrite(Buf(), 1, DataSize, ff);
|
||||
// Check if error
|
||||
if (n != DataSize) err.submit(2104, FileName);
|
||||
// Close file
|
||||
n = fclose(ff);
|
||||
// Check if error
|
||||
if (n) {err.submit(2104, FileName); return;}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int CFileBuffer::GetFileType() {
|
||||
// Detect file type
|
||||
if (FileType) return FileType; // File type already known
|
||||
if (!DataSize) return 0; // No file
|
||||
if (!Buf()) return 0; // No contents
|
||||
|
||||
uint32 namelen = FileName ? (uint32)strlen(FileName) : 0;
|
||||
|
||||
if (strncmp(Buf(),"!<arch>",7) == 0) {
|
||||
// UNIX style library. Contains members of file type COFF, ELF or MACHO
|
||||
FileType = FILETYPE_LIBRARY;
|
||||
}
|
||||
else if (strncmp(Buf(),ELFMAG,4) == 0) {
|
||||
// ELF file
|
||||
FileType = FILETYPE_ELF;
|
||||
Executable = Get<Elf32_Ehdr>(0).e_type != ET_REL;
|
||||
switch (Buf()[EI_CLASS]) {
|
||||
case ELFCLASS32:
|
||||
WordSize = 32; break;
|
||||
case ELFCLASS64:
|
||||
WordSize = 64; break;
|
||||
}
|
||||
}
|
||||
else if (Get<uint32>(0) == MAC_MAGIC_32) {
|
||||
// Mach-O 32 little endian
|
||||
FileType = FILETYPE_MACHO_LE;
|
||||
WordSize = 32;
|
||||
Executable = Get<MAC_header_32>(0).filetype != MAC_OBJECT;
|
||||
}
|
||||
else if (Get<uint32>(0) == MAC_MAGIC_64) {
|
||||
// Mach-O 64 little endian
|
||||
FileType = FILETYPE_MACHO_LE;
|
||||
WordSize = 64;
|
||||
Executable = Get<MAC_header_64>(0).filetype != MAC_OBJECT;
|
||||
}
|
||||
else if (Get<uint32>(0) == MAC_CIGAM_32) {
|
||||
// Mach-O 32 big endian
|
||||
FileType = FILETYPE_MACHO_BE;
|
||||
WordSize = 32;
|
||||
}
|
||||
else if (Get<uint32>(0) == MAC_CIGAM_64) {
|
||||
// Mach-O 64 big endian
|
||||
FileType = FILETYPE_MACHO_BE;
|
||||
WordSize = 64;
|
||||
}
|
||||
else if (Get<uint32>(0) == MAC_CIGAM_UNIV) {
|
||||
// MacIntosh universal binary
|
||||
FileType = FILETYPE_MAC_UNIVBIN;
|
||||
WordSize = 0;
|
||||
}
|
||||
else if (Get<uint32>(0) == 0xFFFF0000 || Get<uint32>(0) == 0x10000) {
|
||||
// Windows subtypes:
|
||||
if (Get<uint16>(4) == 0) {
|
||||
// This type only occurs when attempting to extract a member from an import library
|
||||
FileType = IMPORT_LIBRARY_MEMBER;
|
||||
}
|
||||
else if (Get<uint16>(4) == 1) {
|
||||
// Whole program optimization intermediate file for MS compiler. Undocumented
|
||||
FileType = FILETYPE_MS_WPO;
|
||||
}
|
||||
else {
|
||||
// Other subtypes not known
|
||||
FileType = FILETYPE_WIN_UNKNOWN;
|
||||
}
|
||||
// Get word size
|
||||
if (Get<uint16>(6) == PE_MACHINE_I386) {
|
||||
WordSize = 32;
|
||||
}
|
||||
else if (Get<uint16>(6) == PE_MACHINE_X8664) {
|
||||
WordSize = 64;
|
||||
}
|
||||
else {
|
||||
WordSize = 0;
|
||||
}
|
||||
}
|
||||
else if (Get<uint16>(0) == PE_MACHINE_I386) {
|
||||
// COFF/PE 32
|
||||
FileType = FILETYPE_COFF;
|
||||
WordSize = 32;
|
||||
Executable = (Get<SCOFF_FileHeader>(0).Flags & PE_F_EXEC) != 0;
|
||||
}
|
||||
else if (Get<uint16>(0) == PE_MACHINE_X8664) {
|
||||
// COFF64/PE32+
|
||||
FileType = FILETYPE_COFF;
|
||||
WordSize = 64;
|
||||
Executable = (Get<SCOFF_FileHeader>(0).Flags & PE_F_EXEC) != 0;
|
||||
}
|
||||
else if (Get<uint8>(0) == OMF_THEADR) {
|
||||
// OMF 16 or 32
|
||||
FileType = FILETYPE_OMF;
|
||||
// Word size can only be determined by searching through records in file:
|
||||
GetOMFWordSize(); // Determine word size
|
||||
}
|
||||
else if (Get<uint8>(0) == OMF_LIBHEAD) {
|
||||
// OMF Library 16 or 32
|
||||
FileType = FILETYPE_OMFLIBRARY;
|
||||
}
|
||||
else if ((Get<uint16>(0) & 0xFFF9) == 0x5A49) {
|
||||
// DOS file or file with DOS stub
|
||||
FileType = FILETYPE_DOS;
|
||||
WordSize = 16;
|
||||
Executable = 1;
|
||||
uint32 Signature = Get<uint32>(0x3C);
|
||||
if (Signature + 8 < DataSize) {
|
||||
if (Get<uint16>(Signature) == 0x454E) {
|
||||
// Windows 3.x file
|
||||
FileType = FILETYPE_WIN3X;
|
||||
}
|
||||
else if (Get<uint16>(Signature) == 0x4550) {
|
||||
// COFF file
|
||||
uint16 MachineType = Get<uint16>(Signature + 4);
|
||||
if (MachineType == PE_MACHINE_I386) {
|
||||
FileType = FILETYPE_COFF;
|
||||
WordSize = 32;
|
||||
}
|
||||
else if (MachineType == PE_MACHINE_X8664) {
|
||||
FileType = FILETYPE_COFF;
|
||||
WordSize = 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (namelen > 4 && stricmp(FileName + namelen - 4, ".com") == 0) {
|
||||
// DOS .com file recognized only from its extension
|
||||
FileType = FILETYPE_DOS;
|
||||
WordSize = 16; Executable = 1;
|
||||
}
|
||||
else if (Get<uint16>(0) == 0 && namelen > 4 && stricmp(FileName + namelen - 4, ".obj") == 0) {
|
||||
// Possibly alias record in COFF library
|
||||
FileType = FILETYPE_COFF;
|
||||
WordSize = 0;
|
||||
Executable = 0;
|
||||
}
|
||||
else {
|
||||
// Unknown file type
|
||||
int utype = Get<uint32>(0);
|
||||
err.submit(2018, utype, FileName);
|
||||
FileType = 0;
|
||||
}
|
||||
return FileType;
|
||||
}
|
||||
|
||||
|
||||
char const * CFileBuffer::GetFileFormatName(int FileType) {
|
||||
// Get name of file format type
|
||||
return Lookup (FileFormatNames, FileType);
|
||||
}
|
||||
|
||||
|
||||
void CFileBuffer::SetFileType(int type) {
|
||||
// Set file format type
|
||||
FileType = type;
|
||||
}
|
||||
|
||||
void CFileBuffer::Reset() {
|
||||
// Set all members to zero
|
||||
SetSize(0); // Deallocate memory buffer
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
char * CFileBuffer::SetFileNameExtension(const char * f) {
|
||||
// Set file name extension according to FileType
|
||||
static char name[MAXFILENAMELENGTH+8];
|
||||
int i;
|
||||
|
||||
if (strlen(f) > MAXFILENAMELENGTH) err.submit(2203, f);
|
||||
strncpy(name, f, MAXFILENAMELENGTH);
|
||||
|
||||
// Search for last '.' in file name
|
||||
for (i = (int)strlen(name)-1; i > 0; i--) if (name[i] == '.') break;
|
||||
if (i < 1) {
|
||||
// '.' not found. Append '.' to name
|
||||
i = (int)strlen(name); if (i > MAXFILENAMELENGTH-4) i = MAXFILENAMELENGTH-4;
|
||||
}
|
||||
// Get default extension
|
||||
if (cmd.OutputType == FILETYPE_ASM) {
|
||||
strcpy(name+i, ".asm"); // Assembly file
|
||||
}
|
||||
else if (cmd.OutputType == FILETYPE_COFF || cmd.OutputType == FILETYPE_OMF) {
|
||||
if ((FileType & (FILETYPE_LIBRARY | FILETYPE_OMFLIBRARY)) || (cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER)) {
|
||||
strcpy(name+i, ".lib"); // Windows function library
|
||||
}
|
||||
else {
|
||||
strcpy(name+i, ".obj"); // Windows object file
|
||||
}
|
||||
}
|
||||
else { // output type is ELF or MACHO
|
||||
if ((FileType & (FILETYPE_LIBRARY | FILETYPE_OMFLIBRARY)) || (cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER)) {
|
||||
strcpy(name+i, ".a"); // Linux/BSD/Mac function library
|
||||
}
|
||||
else {
|
||||
strcpy(name+i, ".o"); // Linux/BSD/Mac object file
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
void CFileBuffer::CheckOutputFileName() {
|
||||
// Make output file name or check that requested name is valid
|
||||
if (!(cmd.FileOptions & CMDL_FILE_OUTPUT)) return;
|
||||
|
||||
OutputFileName = cmd.OutputFile;
|
||||
if (OutputFileName == 0) {
|
||||
// Output file name not specified. Make filename
|
||||
OutputFileName = cmd.OutputFile = SetFileNameExtension(FileName);
|
||||
}
|
||||
if (strcmp(FileName,OutputFileName) == 0 && !(cmd.FileOptions & CMDL_FILE_IN_OUT_SAME)) {
|
||||
// Input and output files have same name
|
||||
err.submit(2005, FileName);
|
||||
}
|
||||
}
|
||||
|
||||
void operator >> (CFileBuffer & a, CFileBuffer & b) {
|
||||
// Transfer ownership of buffer and other properties from a to b
|
||||
b.SetSize(0); // De-allocate old buffer from target if it has one
|
||||
b.buffer = a.buffer; // Transfer buffer
|
||||
a.buffer = 0; // Remove buffer from source, so that buffer has only one owner
|
||||
|
||||
// Copy properties
|
||||
b.DataSize = a.GetDataSize(); // Size of data, offset to vacant space
|
||||
b.BufferSize = a.GetBufferSize(); // Size of allocated buffer
|
||||
b.NumEntries = a.GetNumEntries(); // Number of objects pushed
|
||||
b.Executable = a.Executable; // File is executable
|
||||
if (a.WordSize) b.WordSize = a.WordSize; // Segment word size (16, 32, 64)
|
||||
if (a.FileName) b.FileName = a.FileName; // Name of input file
|
||||
if (a.OutputFileName) b.OutputFileName = a.OutputFileName;// Name of output file
|
||||
if (a.GetFileType()) b.FileType = a.GetFileType(); // Object file type
|
||||
a.SetSize(0); // Reset a's properties
|
||||
}
|
||||
|
||||
void CFileBuffer::GetOMFWordSize() {
|
||||
// Determine word size for OMF file.
|
||||
// There is no simple way to get the word size. Looking for odd-numbered
|
||||
// record types is not sufficient. A 32-bit OMF file may use 16-bit SEGDEF
|
||||
// records. We have to look for segments with the 'P' attribute set. And
|
||||
// even this is not completely safe, because MASM may generate empty 32-bit
|
||||
// segments so we have to look only at segments with nonzero size.
|
||||
// We can still have any mixture of 16- and 32-bit segments, though, so no
|
||||
// method is absolutely safe.
|
||||
|
||||
// We have to parse through all records in file buffer
|
||||
uint8 RecordType; // Type of current record
|
||||
uint32 RecordStart; // Index to start of current record
|
||||
uint32 RecordEnd; // Index to end of current record
|
||||
uint32 RecordLength; // Length of current record
|
||||
uint32 Index = 0; // Current offset from buffer while reading
|
||||
OMF_SAttrib SegAttr; // Segment attributed
|
||||
uint32 SegLength; // Segment length
|
||||
|
||||
WordSize = 16; // WordSize = 16 if no 32 bit records found
|
||||
|
||||
while (Index < GetDataSize()) {
|
||||
RecordStart = Index; // Record starts here
|
||||
RecordType = Get<uint8>(Index++); // Get first byte of record = type
|
||||
RecordLength = Get<uint16>(Index); // Next two bytes = length
|
||||
Index += 2;
|
||||
RecordEnd = RecordStart + RecordLength + 3;// End of record
|
||||
if (RecordEnd > GetDataSize()) {
|
||||
// Record goes beyond end of file
|
||||
err.submit(2301); break;
|
||||
}
|
||||
if ((RecordType & 1) && RecordType < OMF_LIBHEAD) { // Odd-numbered type means 32 bit
|
||||
WordSize = 32; // ..but this method is not safe
|
||||
}
|
||||
if ((RecordType & 0xFE) == OMF_SEGDEF) { // Segment definition record
|
||||
SegAttr.b = Get<uint8>(Index++); // Get segment attributes
|
||||
if (SegAttr.u.A == 0) {
|
||||
// Frame and Offset only included if A = 0
|
||||
Index += 2+1;
|
||||
}
|
||||
SegLength = (RecordType & 1) ? Get<uint32>(Index) : Get<uint16>(Index); // Segment length
|
||||
|
||||
if (SegAttr.u.P && SegLength) { // if segment has P attribute and nonzero length
|
||||
WordSize = 32; // .. then it is a 32-bit segment
|
||||
}
|
||||
}
|
||||
Index = RecordEnd; // Point to next record
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Class CTextFileBuffer is used for building text files
|
||||
// Constructor
|
||||
CTextFileBuffer::CTextFileBuffer() {
|
||||
column = 0;
|
||||
// Use UNIX linefeeds only if GASM output
|
||||
LineType = (cmd.SubType == SUBTYPE_GASM) ? 1 : 0;
|
||||
}
|
||||
|
||||
void CTextFileBuffer::Put(const char * text) {
|
||||
// Write text string to buffer
|
||||
uint32 len = (uint32)strlen(text); // Length of text
|
||||
Push(text, len); // Add to buffer without terminating zero
|
||||
column += len; // Update column
|
||||
}
|
||||
|
||||
void CTextFileBuffer::Put(const char character) {
|
||||
// Write single character to buffer
|
||||
Push(&character, 1); // Add to buffer
|
||||
column ++; // Update column
|
||||
}
|
||||
|
||||
void CTextFileBuffer::NewLine() {
|
||||
// Add linefeed
|
||||
if (LineType == 0) {
|
||||
Push("\r\n", 2); // DOS/Windows style linefeed
|
||||
}
|
||||
else {
|
||||
Push("\n", 1); // UNIX style linefeed
|
||||
}
|
||||
column = 0; // Reset column
|
||||
}
|
||||
|
||||
void CTextFileBuffer::Tabulate(uint32 i) {
|
||||
// Insert spaces until column i
|
||||
uint32 j;
|
||||
if (i > column) { // Only insert spaces if we are not already past i
|
||||
for (j = column; j < i; j++) Push(" ", 1); // Insert i - column spaces
|
||||
column = i; // Update column
|
||||
}
|
||||
}
|
||||
|
||||
void CTextFileBuffer::PutDecimal(int32 x, int IsSigned) {
|
||||
// Write decimal number to buffer, unsigned or signed
|
||||
char text[16];
|
||||
sprintf(text, IsSigned ? "%i" : "%u", x);
|
||||
Put(text);
|
||||
}
|
||||
|
||||
void CTextFileBuffer::PutHex(uint8 x, int MasmForm) {
|
||||
// Write hexadecimal 8 bit number to buffer
|
||||
// If MasmForm >= 1 then the function will write the number in a
|
||||
// way that can be read by the assembler, e.g. 0FFH or 0xFF
|
||||
char text[16];
|
||||
if (MasmForm && cmd.SubType == SUBTYPE_GASM) {
|
||||
// Needs 0x prefix
|
||||
sprintf(text, "0x%02X", x);
|
||||
Put(text);
|
||||
return;
|
||||
}
|
||||
if (MasmForm && x >= 0xA0) {
|
||||
Put("0"); // Make sure it doesn't begin with a letter
|
||||
}
|
||||
sprintf(text, "%02X", x);
|
||||
Put(text);
|
||||
if (MasmForm) Put("H");
|
||||
}
|
||||
|
||||
void CTextFileBuffer::PutHex(uint16 x, int MasmForm) {
|
||||
// Write hexadecimal 16 bit number to buffer
|
||||
// If MasmForm >= 1 then the function will write the number in a
|
||||
// way that can be read by the assembler, e.g. 0FFH or 0xFF
|
||||
// If MasmForm == 2 then leading zeroes are stripped
|
||||
char text[16];
|
||||
if (MasmForm && cmd.SubType == SUBTYPE_GASM) {
|
||||
// Needs 0x prefix
|
||||
sprintf(text, MasmForm==1 ? "0x%04X" : "0x%X", x);
|
||||
Put(text);
|
||||
return;
|
||||
}
|
||||
sprintf(text, (MasmForm < 2) ? "%04X" : "%X", x);
|
||||
// Check if leading zero needed
|
||||
if (MasmForm && text[0] > '9') {
|
||||
Put("0"); // Leading zero needed
|
||||
}
|
||||
Put(text);
|
||||
if (MasmForm) Put("H");
|
||||
}
|
||||
|
||||
void CTextFileBuffer::PutHex(uint32 x, int MasmForm) {
|
||||
// Write hexadecimal 32 bit number to buffer
|
||||
// If MasmForm >= 1 then the function will write the number in a
|
||||
// way that can be read by the assembler, e.g. 0FFH or 0xFF
|
||||
// If MasmForm == 2 then leading zeroes are stripped
|
||||
char text[16];
|
||||
if (MasmForm && cmd.SubType == SUBTYPE_GASM) {
|
||||
// Needs 0x prefix
|
||||
sprintf(text, MasmForm==1 ? "0x%08X" : "0x%X", x);
|
||||
Put(text);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(text, (MasmForm < 2) ? "%08X" : "%X", x);
|
||||
// Check if leading zero needed
|
||||
if (MasmForm && text[0] > '9') {
|
||||
Put("0"); // Leading zero needed
|
||||
}
|
||||
Put(text);
|
||||
if (MasmForm) Put("H");
|
||||
}
|
||||
|
||||
void CTextFileBuffer::PutHex(uint64 x, int MasmForm) {
|
||||
// Write unsigned hexadecimal 64 bit number to buffer
|
||||
// If MasmForm >= 1 then the function will write the number in a
|
||||
// way that can be read by the assembler, e.g. 0FFH or 0xFF
|
||||
// If MasmForm == 2 then leading zeroes are stripped
|
||||
char text[32];
|
||||
if (MasmForm < 2) { // Print all digits
|
||||
sprintf(text, "%08X%08X", HighDWord(x), uint32(x));
|
||||
}
|
||||
else { // Skip leading zeroes
|
||||
if (HighDWord(x)) {
|
||||
sprintf(text, "%X%08X", HighDWord(x), uint32(x));
|
||||
}
|
||||
else {
|
||||
sprintf(text, "%X", uint32(x));
|
||||
}
|
||||
}
|
||||
if (MasmForm) {
|
||||
if (cmd.SubType == SUBTYPE_GASM) {
|
||||
// Needs 0x prefix
|
||||
Put("0x");
|
||||
Put(text);
|
||||
}
|
||||
else {
|
||||
// use 0FFH form
|
||||
if (text[0] > '9') Put("0"); // Leading zero needed
|
||||
Put(text);
|
||||
Put("H");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// write hexadecimal number only
|
||||
Put(text);
|
||||
}
|
||||
}
|
||||
|
||||
void CTextFileBuffer::PutFloat(float x) {
|
||||
// Write floating point number to buffer
|
||||
char text[64];
|
||||
sprintf(text, "%.7G", x);
|
||||
Put(text);
|
||||
}
|
||||
|
||||
void CTextFileBuffer::PutFloat(double x) {
|
||||
// Write floating point number to buffer
|
||||
char text[64];
|
||||
sprintf(text, "%.16G", x);
|
||||
Put(text);
|
||||
}
|
Reference in New Issue
Block a user