6 // (C) 2010 Underground Software
8 // JLH = James Hammons <jlhamm@acm.org>
9 // JPM = Jean-Paul Mari <djipi.mari@gmail.com>
12 // --- ---------- ------------------------------------------------------------
13 // JLH 01/16/2010 Created this log ;-)
14 // JLH 02/28/2010 Added functions to look inside .ZIP files and handle contents
15 // JLH 06/01/2012 Added function to check ZIP file CRCs against file DB
16 // JPM June/2016 Visual Studio support, ELF format support and Soft debugger support
17 // JPM 07/15/2016 DWARF format support
18 // JPM 04/06/2019 Added ELF sections check
19 // JPM 03/12/2020 Added ELF section types check and new error messages
20 // JPM Aug./2020 ELF executable file information
25 #include "_MSC_VER/config.h"
29 #include <sys/types.h>
37 #include "universalhdr.h"
43 #include "debugger/ELFManager.h"
44 #include "debugger/DBGManager.h"
48 // Private function prototypes
50 static int gzfilelength(gzFile gd
);
51 //#if defined(_MSC_VER) || defined(__MINGW64__)|| defined(__MINGW32__) || defined(__CYGWIN__)
52 static bool CheckExtension(const uint8_t *filename
, const char *ext
);
54 //static bool CheckExtension(const char * filename, const char * ext);
56 //static int ParseFileType(uint8_t header1, uint8_t header2, uint32_t size);
58 // Private variables/enums
62 // Generic ROM loading
64 uint32_t JaguarLoadROM(uint8_t * &rom
, char * path
)
66 // We really should have some kind of sanity checking for the ROM size here to prevent
67 // a buffer overflow... !!! FIX !!!
69 #pragma message("Warning: !!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!")
71 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
75 WriteLog("FILE: JaguarLoadROM attempting to load file '%s'...", path
);
76 char * ext
= strrchr(path
, '.');
78 // No filename extension == YUO FAIL IT (it is loading the file).
79 // This is naive, but it works. But should probably come up with something a little
80 // more robust, to prevent problems with dopes trying to exploit this.
83 WriteLog("FAILED!\n");
87 WriteLog("\nFILE: Succeeded in finding extension (%s)!\n", ext
);
88 WriteLog("FILE: Loading \"%s\"...", path
);
90 if (strcasecmp(ext
, ".zip") == 0)
92 // Handle ZIP file loading here...
93 WriteLog("(ZIPped)...");
95 // uint8_t * buffer = NULL;
96 // romSize = GetFileFromZIP(path, FT_SOFTWARE, buffer);
97 romSize
= GetFileFromZIP(path
, FT_SOFTWARE
, rom
);
101 WriteLog("Failed!\n");
105 // memcpy(rom, buffer, romSize);
110 // Handle gzipped files transparently [Adam Green]...
112 gzFile fp
= gzopen(path
, "rb");
116 WriteLog("Failed!\n");
120 romSize
= gzfilelength(fp
);
121 rom
= new uint8_t[romSize
];
122 gzseek(fp
, 0, SEEK_SET
);
123 gzread(fp
, rom
, romSize
);
127 WriteLog("OK (%i bytes)\n", romSize
);
134 // Jaguar file loading
135 // We do a more intelligent file analysis here instead of relying on (possible
136 // false) file extensions which people don't seem to give two shits about
139 bool JaguarLoadFile(char * path
)
142 GElf_Ehdr ElfEhdr
, *PtrGElfEhdr
;
144 Elf_Data
*PtrElfData
;
145 GElf_Shdr GElfShdr
, *PtrGElfShdr
;
147 uint8_t *buffer
= NULL
;
149 size_t ElfSectionNameType
;
150 int DBGType
= DBG_NO_TYPE
;
153 struct stat _statbuf
;
155 jaguarROMSize
= JaguarLoadROM(buffer
, path
);
157 if (jaguarROMSize
== 0)
159 // It's up to the GUI to report errors, not us. :-)
160 WriteLog("FILE: Could not load ROM from file \"%s\"...\nAborting load!\n", path
);
164 jaguarMainROMCRC32
= crc32_calcCheckSum(buffer
, jaguarROMSize
);
165 WriteLog("CRC: %08X\n", (unsigned int)jaguarMainROMCRC32
);
166 // TODO: Check for EEPROM file in ZIP file. If there is no EEPROM in the user's EEPROM
167 // directory, copy the one from the ZIP file, if it exists.
169 jaguarRunAddress
= 0x802000; // For non-BIOS runs, this is true
170 int fileType
= ParseFileType(buffer
, jaguarROMSize
);
171 jaguarCartInserted
= false;
174 if (fileType
== JST_ROM
)
176 jaguarCartInserted
= true;
177 memcpy(jagMemSpace
+ 0x800000, buffer
, jaguarROMSize
);
178 // Checking something...
179 jaguarRunAddress
= GET32(jagMemSpace
, 0x800404);
180 WriteLog("FILE: Cartridge run address is reported as $%X...\n", jaguarRunAddress
);
184 else if (fileType
== JST_ALPINE
)
186 // File extension ".ROM": Alpine image that loads/runs at $802000
187 WriteLog("FILE: Setting up Alpine ROM... Run address: 00802000, length: %08X\n", jaguarROMSize
);
188 memset(jagMemSpace
+ 0x800000, 0xFF, 0x2000);
189 memcpy(jagMemSpace
+ 0x802000, buffer
, jaguarROMSize
);
192 // Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
193 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
194 // This kludge works! Yeah!
195 SET32(jaguarMainRAM
, 0x10, 0x00001000);
196 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
199 else if (fileType
== JST_ELF32
)
203 char *PtrELFExe
= (char *)ELFManager_ExeCopy(buffer
, jaguarROMSize
);
205 if (PtrELFExe
!= NULL
)
207 // check the ELF version
208 if ((elf_version(EV_CURRENT
) != EV_NONE
) && (ElfMem
= ELFManager_MemOpen(PtrELFExe
, jaguarROMSize
)))
210 // get the file information
211 stat(path
, &_statbuf
);
213 if (ELFManager_DwarfInit(ElfMem
, _statbuf
))
215 DBGType
|= DBG_ELFDWARF
;
218 if (!elf_getshdrnum(ElfMem
, &NbrSect
))
220 if (((PtrGElfEhdr
= gelf_getehdr(ElfMem
, &ElfEhdr
)) != NULL
) && ((PtrElfScn
= elf_getscn(ElfMem
, 0)) != NULL
))
222 for (error
= false; (PtrElfScn
!= NULL
) && (error
== false); PtrElfScn
= elf_nextscn(ElfMem
, PtrElfScn
))
226 if ((PtrGElfShdr
= gelf_getshdr(PtrElfScn
, &GElfShdr
)) == NULL
)
232 NameSection
= elf_strptr(ElfMem
, PtrGElfEhdr
->e_shstrndx
, (size_t)PtrGElfShdr
->sh_name
);
233 WriteLog("FILE: ELF Section %s found\n", NameSection
);
235 if (((ElfSectionNameType
= ELFManager_GetSectionType(NameSection
)) == ELF_NO_TYPE
) && vjs
.ELFSectionsCheck
)
237 WriteLog("FILE: ELF Section %s not recognized\n", NameSection
);
242 switch (PtrGElfShdr
->sh_type
)
248 if ((PtrGElfShdr
->sh_flags
& (SHF_ALLOC
| SHF_WRITE
| SHF_EXECINSTR
)))
250 if (PtrGElfShdr
->sh_addr
>= 0x800000)
252 memcpy(jagMemSpace
+ PtrGElfShdr
->sh_addr
, buffer
+ PtrGElfShdr
->sh_offset
, PtrGElfShdr
->sh_size
);
257 memcpy(jaguarMainRAM
+ PtrGElfShdr
->sh_addr
, buffer
+ PtrGElfShdr
->sh_offset
, PtrGElfShdr
->sh_size
);
262 switch (ElfSectionNameType
)
265 case ELF_debug_abbrev_TYPE
:
266 case ELF_debug_aranges_TYPE
:
267 case ELF_debug_frame_TYPE
:
268 case ELF_debug_info_TYPE
:
269 case ELF_debug_line_TYPE
:
270 case ELF_debug_loc_TYPE
:
271 case ELF_debug_macinfo_TYPE
:
272 case ELF_debug_pubnames_TYPE
:
273 case ELF_debug_pubtypes_TYPE
:
274 case ELF_debug_ranges_TYPE
:
275 case ELF_debug_str_TYPE
:
276 case ELF_debug_types_TYPE
:
282 case ELF_comment_TYPE
:
286 WriteLog("FILE: ELF section %s is not recognized\n", NameSection
);
298 while ((error
== false) && ((PtrElfData
= elf_getdata(PtrElfScn
, PtrElfData
)) != NULL
))
300 if (!ELFManager_AddTab(PtrElfData
, ElfSectionNameType
))
302 WriteLog("FILE: ELF tab cannot be allocated\n");
309 WriteLog("FILE: ELF SHT type %i not recognized\n", PtrGElfShdr
->sh_type
);
317 // Set the executable address
318 jaguarRunAddress
= (uint32_t)PtrGElfEhdr
->e_entry
;
319 WriteLog("FILE: Setting up ELF 32bits... Run address: %08X\n", jaguarRunAddress
);
328 WriteLog("FILE: Cannot get the number of the ELF sections\n");
335 WriteLog("FILE: libelf version is not recognized or libelf memory cannot be opened\n");
341 WriteLog("FILE: ELFManager cannot allocate memory\n");
348 WriteLog("FILE: ELF parsing error\n");
350 if ((err
= elf_errno()))
352 WriteLog("FILE: ELF error: %s\n", elf_errmsg(err
));
359 DBGManager_SetType(DBGType
);
363 else if (fileType
== JST_ABS_TYPE1
)
365 // For ABS type 1, run address == load address
366 uint32_t loadAddress
= GET32(buffer
, 0x16),
367 codeSize
= GET32(buffer
, 0x02) + GET32(buffer
, 0x06);
368 WriteLog("FILE: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress
, codeSize
);
369 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x24, codeSize
);
371 jaguarRunAddress
= loadAddress
;
374 else if (fileType
== JST_ABS_TYPE2
)
376 uint32_t loadAddress
= GET32(buffer
, 0x28), runAddress
= GET32(buffer
, 0x24),
377 codeSize
= GET32(buffer
, 0x18) + GET32(buffer
, 0x1C);
378 WriteLog("FILE: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress
, codeSize
);
379 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0xA8, codeSize
);
381 jaguarRunAddress
= runAddress
;
384 // NB: This is *wrong*
386 Basically, if there is no "JAG" at position $1C, then the long there is the load/start
387 address in LITTLE ENDIAN.
388 If "JAG" is present, the the next character ("R" or "L") determines the size of the
389 JagServer command (2 bytes vs. 4). Following that are the commands themselves;
390 typically it will either be 2 (load) or 3 (load & run). Command headers go like so:
409 10: (Poll for commands)
411 12: (Load & run user program)
412 filname, terminated with NULL
417 else if (fileType
== JST_JAGSERVER
)
419 // This kind of shiaut should be in the detection code below...
420 // (and now it is! :-)
421 // if (buffer[0x1C] == 'J' && buffer[0x1D] == 'A' && buffer[0x1E] == 'G')
423 // Still need to do some checking here for type 2 vs. type 3. This assumes 3
424 // Also, JAGR vs. JAGL (word command size vs. long command size)
425 uint32_t loadAddress
= GET32(buffer
, 0x22), runAddress
= GET32(buffer
, 0x2A);
426 WriteLog("FILE: Setting up homebrew (Jag Server)... Run address: $%X, length: $%X\n", runAddress
, jaguarROMSize
- 0x2E);
427 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x2E, jaguarROMSize
- 0x2E);
429 jaguarRunAddress
= runAddress
;
431 // Hmm. Is this kludge necessary?
432 SET32(jaguarMainRAM
, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction)
433 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
437 // else // Special WTFOMGBBQ type here...
439 // uint32_t loadAddress = (buffer[0x1F] << 24) | (buffer[0x1E] << 16) | (buffer[0x1D] << 8) | buffer[0x1C];
440 // WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress, jaguarROMSize - 0x20);
441 // memcpy(jagMemSpace + loadAddress, buffer + 0x20, jaguarROMSize - 0x20);
443 // jaguarRunAddress = loadAddress;
447 else if (fileType
== JST_WTFOMGBBQ
)
449 uint32_t loadAddress
= (buffer
[0x1F] << 24) | (buffer
[0x1E] << 16) | (buffer
[0x1D] << 8) | buffer
[0x1C];
450 WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress
, jaguarROMSize
- 0x20);
451 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x20, jaguarROMSize
- 0x20);
453 jaguarRunAddress
= loadAddress
;
457 // We can assume we have JST_NONE at this point. :-P
458 WriteLog("FILE: Failed to load headerless file.\n");
464 // "Debugger" file loading
465 // To keep the things separate between "Debugger" and "Alpine" loading until usage clarification has been done
467 bool DebuggerLoadFile(char * path
)
469 return (AlpineLoadFile(path
));
474 // "Alpine" file loading
475 // Since the developers were coming after us with torches and pitchforks, we
476 // decided to allow this kind of thing. ;-) But ONLY FOR THE DEVS, DAMMIT! >:-U
479 bool AlpineLoadFile(char * path
)
481 uint8_t * buffer
= NULL
;
482 jaguarROMSize
= JaguarLoadROM(buffer
, path
);
484 if (jaguarROMSize
== 0)
486 // It's up to the GUI to deal with failure, not us. ;-)
487 WriteLog("FILE: Could not load Alpine from file \"%s\"...\nAborting load!\n", path
);
491 jaguarMainROMCRC32
= crc32_calcCheckSum(buffer
, jaguarROMSize
);
492 WriteLog("FILE: CRC is %08X\n", (unsigned int)jaguarMainROMCRC32
);
495 jaguarRunAddress
= 0x802000;
497 WriteLog("FILE: Setting up Alpine ROM with non-standard length... Run address: 00802000, length: %08X\n", jaguarROMSize
);
499 memset(jagMemSpace
+ 0x800000, 0xFF, 0x2000);
500 memcpy(jagMemSpace
+ 0x802000, buffer
, jaguarROMSize
);
503 // Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
504 // Try setting the vector to say, $1000 and putting an instruction there
505 // that loops forever:
506 // This kludge works! Yeah!
507 SET32(jaguarMainRAM
, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction)
508 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
515 // Get the length of a (possibly) gzipped file
517 static int gzfilelength(gzFile gd
)
519 int size
= 0, length
= 0;
520 unsigned char buffer
[0x10000];
526 // Read in chunks until EOF
527 size
= gzread(gd
, buffer
, 0x10000);
542 // Compare extension to passed in filename. If equal, return true; otherwise false.
544 //#if defined(_MSC_VER) || defined(__MINGW64__)|| defined(__MINGW32__) || defined(__CYGWIN__)
545 static bool CheckExtension(const uint8_t *filename
, const char *ext
)
547 //static bool CheckExtension(const char * filename, const char * ext)
550 // Sanity checking...
551 if ((filename
== NULL
) || (ext
== NULL
))
554 const char * filenameExt
= strrchr((const char *)filename
, '.'); // Get the file's extension (if any)
556 if (filenameExt
== NULL
)
559 return (strcasecmp(filenameExt
, ext
) == 0 ? true : false);
564 // Get file from .ZIP
565 // Returns the size of the file inside the .ZIP file that we're looking at
566 // NOTE: If the thing we're looking for is found, it allocates it in the passed in buffer.
567 // Which means we have to deallocate it later.
569 uint32_t GetFileFromZIP(const char * zipFile
, FileType type
, uint8_t * &buffer
)
571 // NOTE: We could easily check for this by discarding anything that's larger than the RAM/ROM
572 // size of the Jaguar console.
573 #if defined(_MSC_VER)
574 #pragma message("Warning: !!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!")
576 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
578 const char ftStrings
[5][32] = { "Software", "EEPROM", "Label", "Box Art", "Controller Overlay" };
579 // ZIP * zip = openzip(0, 0, zipFile);
580 FILE * zip
= fopen(zipFile
, "rb");
584 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
592 // The order is here is important: If the file is found, we need to short-circuit the
593 // readzip() call because otherwise, 'ze' will be pointing to the wrong file!
594 // while (!found && readzip(zip))
595 while (!found
&& GetZIPHeader(zip
, ze
))
599 // Here we simply rely on the file extension to tell the truth, but we know
600 // that extensions lie like sons-a-bitches. So this is naive, we need to do
601 // something a little more robust to keep bad things from happening here.
602 #if defined(_MSC_VER)
603 #pragma message("Warning: !!! Checking for image by extension can be fooled !!!")
605 #warning "!!! Checking for image by extension can be fooled !!!"
607 if ((type
== FT_LABEL
) && (CheckExtension(ze
.filename
, ".png") || CheckExtension(ze
.filename
, ".jpg") || CheckExtension(ze
.filename
, ".gif")))
610 WriteLog("FILE: Found image file '%s'.\n", ze
.filename
);
613 if ((type
== FT_SOFTWARE
) && (CheckExtension(ze
.filename
, ".j64")
614 || CheckExtension(ze
.filename
, ".rom") || CheckExtension(ze
.filename
, ".abs")
615 || CheckExtension(ze
.filename
, ".cof") || CheckExtension(ze
.filename
, ".coff")
616 || CheckExtension(ze
.filename
, ".jag") || CheckExtension(ze
.filename
, ".elf")))
619 WriteLog("FILE: Found software file '%s'.\n", ze
.filename
);
622 if ((type
== FT_EEPROM
) && (CheckExtension(ze
.filename
, ".eep") || CheckExtension(ze
.filename
, ".eeprom")))
625 WriteLog("FILE: Found EEPROM file '%s'.\n", ze
.filename
);
629 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
632 uint32_t fileSize
= 0;
636 WriteLog("FILE: Uncompressing...");
637 // Insert file size sanity check here...
638 buffer
= new uint8_t[ze
.uncompressedSize
];
640 // if (readuncompresszip(zip, ze.compressedSize, buffer) == 0)
641 // if (UncompressFileFromZIP(zip, ze.compressedSize, buffer) == 0)
642 if (UncompressFileFromZIP(zip
, ze
, buffer
) == 0)
644 fileSize
= ze
.uncompressedSize
;
645 WriteLog("success! (%u bytes)\n", fileSize
);
651 WriteLog("FAILED!\n");
655 // Didn't find what we're looking for...
656 WriteLog("FILE: Failed to find file of type %s...\n", ftStrings
[type
]);
664 uint32_t GetFileDBIdentityFromZIP(const char * zipFile
)
666 FILE * zip
= fopen(zipFile
, "rb");
670 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
676 // Loop through all files in the zip file under consideration
677 while (GetZIPHeader(zip
, ze
))
679 // & loop through all known CRC32s in our file DB to see if it's there!
682 while (romList
[index
].crc32
!= 0xFFFFFF)
684 if (romList
[index
].crc32
== ze
.crc32
)
693 // We didn't find it, so skip the compressed data...
694 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
698 return (uint32_t )-1;
702 bool FindFileInZIPWithCRC32(const char * zipFile
, uint32_t crc
)
704 FILE * zip
= fopen(zipFile
, "rb");
708 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
714 // Loop through all files in the zip file under consideration
715 while (GetZIPHeader(zip
, ze
))
723 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
732 // Parse the file type based upon file size and/or headers.
734 uint32_t ParseFileType(uint8_t * buffer
, uint32_t size
)
736 // Check headers first...
739 if (buffer
[EI_CLASS
] == ELFCLASS32
)
741 if (((BigToLittleEndian16(((Elf32_Ehdr
*)buffer
)->e_machine
) & 0xFF) == EM_68K
) && (BigToLittleEndian16(((Elf32_Ehdr
*)buffer
)->e_type
) == ET_EXEC
) && (buffer
[0] == ELFMAG0
) && (buffer
[1] == ELFMAG1
) && (buffer
[2] == ELFMAG2
) && (buffer
[3] == ELFMAG3
))
746 if (buffer
[0] == 0x60 && buffer
[1] == 0x1B)
747 return JST_ABS_TYPE1
;
750 if (buffer
[0] == 0x01 && buffer
[1] == 0x50)
751 return JST_ABS_TYPE2
;
753 // Jag Server & other old shite
754 if (buffer
[0] == 0x60 && buffer
[1] == 0x1A)
756 if (buffer
[0x1C] == 'J' && buffer
[0x1D] == 'A' && buffer
[0x1E] == 'G')
757 return JST_JAGSERVER
;
759 return JST_WTFOMGBBQ
;
762 // And if that fails, try file sizes...
764 // If the file size is divisible by 1M, we probably have an regular ROM.
765 // We can also check our CRC32 against the internal ROM database to be sure.
766 // (We also check for the Memory Track cartridge size here as well...)
767 if ((size
% 1048576) == 0 || size
== 131072)
770 // If the file size + 8192 bytes is divisible by 1M, we probably have an
771 // Alpine format ROM.
772 if (((size
+ 8192) % 1048576) == 0)
780 // Check for universal header
782 bool HasUniversalHeader(uint8_t * rom
, uint32_t romSize
)
788 for(int i
=0; i
<8192; i
++)
789 if (rom
[i
] != universalCartHeader
[i
])
799 Stubulator ROM vectors...
800 handler 001 at $00E00008
801 handler 002 at $00E008DE
802 handler 003 at $00E008E2
803 handler 004 at $00E008E6
804 handler 005 at $00E008EA
805 handler 006 at $00E008EE
806 handler 007 at $00E008F2
807 handler 008 at $00E0054A
808 handler 009 at $00E008FA
809 handler 010 at $00000000
810 handler 011 at $00000000
811 handler 012 at $00E008FE
812 handler 013 at $00E00902
813 handler 014 at $00E00906
814 handler 015 at $00E0090A
815 handler 016 at $00E0090E
816 handler 017 at $00E00912
817 handler 018 at $00E00916
818 handler 019 at $00E0091A
819 handler 020 at $00E0091E
820 handler 021 at $00E00922
821 handler 022 at $00E00926
822 handler 023 at $00E0092A
823 handler 024 at $00E0092E
824 handler 025 at $00E0107A
825 handler 026 at $00E0107A
826 handler 027 at $00E0107A
827 handler 028 at $00E008DA
828 handler 029 at $00E0107A
829 handler 030 at $00E0107A
830 handler 031 at $00E0107A
831 handler 032 at $00000000
833 Let's try setting up the illegal instruction vector for a stubulated jaguar...
835 SET32(jaguar_mainRam, 0x08, 0x00E008DE);
836 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
837 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
838 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
841 ABS Format sleuthing (LBUGDEMO.ABS):
843 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
844 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
847 DRI-format file detected...
848 Text segment size = 0x0000050c bytes
849 Data segment size = 0x000462c0 bytes
850 BSS Segment size = 0x00000428 bytes
851 Symbol Table size = 0x000012a6 bytes
852 Absolute Address for text segment = 0x00802000
853 Absolute Address for data segment = 0x0080250c
854 Absolute Address for BSS segment = 0x00004000
857 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
858 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
859 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
861 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
862 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
863 000050 00 00 00 00 00 00 00 20
864 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
865 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
866 000078 00 00 00 00 00 00 00 40
867 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
868 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
869 0000a0 00 00 00 00 00 00 00 80
871 Header size is $A8 bytes...
873 BSD/COFF format file detected...
875 Symbol Table offset = 230160 ($00038310)
876 Symbol Table contains 1339 symbol entries ($0000053B)
877 The additional header size is 28 bytes ($001C)
878 Magic Number for RUN_HDR = 0x00000107
879 Text Segment Size = 7632 ($00001DD0)
880 Data Segment Size = 222360 ($00036498)
881 BSS Segment Size = 428928 ($00068B80)
882 Starting Address for executable = 0x00802000
883 Start of Text Segment = 0x00802000
884 Start of Data Segment = 0x00803dd0