// Written by Julien Muchembled. // Fixed by Romain Lievin for Linux. // Further modifications by Sebastian Reichelt, Kevin Kofler and Paul Froissart. // Copyright (c) 2001-2002. All rights reserved. // default: don't include AmigaOS support //#define SUPPORT_AMIGA // This needs to be defined BEFORE including obj2ti.h, since it is used in // that header. #include "obj2ti.h" // default: don't print out extra debugging information //#define TEXT_DEBUG #ifdef TEXT_DEBUG # define DEBUG_PRINT(str...) (printf (str)) #else # define DEBUG_PRINT(str...) #endif // default: catch symbols with unknown class #define CHECK_SYMBOLS #define MAX_VAR_SIZE 65517 __inline unsigned short br2 (void *pp) { unsigned char *p = (unsigned char *) pp; return ((unsigned short) p[0] << 8) + (unsigned short) p[1]; } __inline unsigned long br4 (void *pp) { unsigned char *p = (unsigned char *) pp; return ((unsigned long) p[0] << 24) + ((unsigned long) p[1] << 16) + ((unsigned long) p[2] << 8) + (unsigned long) p[3]; } __inline void bw2 (void *pp, unsigned short w) { unsigned char *p = (unsigned char *) pp; *p++ = (unsigned char)(w>>8); *p = (unsigned char) w; } __inline void bw4 (void *pp, unsigned long dw) { unsigned char *p = (unsigned char *) pp; *p++ = (unsigned char)(dw>>24); *p++ = (unsigned char)(dw>>16); *p++ = (unsigned char)(dw>>8); *p = (unsigned char) dw; } __inline void ba4 (void *p, unsigned long dw) { bw4 (p, br4 (p) + dw); } __inline unsigned short lr2 (void *pp) { unsigned char *p = (unsigned char *) pp; return (unsigned short) p[0] + ((unsigned short) p[1] << 8); } __inline unsigned long lr4 (void *pp) { unsigned char *p = (unsigned char *) pp; return (unsigned long) p[0] + ((unsigned long) p[1] << 8) + ((unsigned long) p[2] << 16) + ((unsigned long) p[3] << 24); } __inline void lw2 (void *pp, unsigned short w) { unsigned char *p = (unsigned char *) pp; *p++ = (unsigned char) w; *p = (unsigned char)(w>>8); } __inline void lw4 (void *pp, unsigned long dw) { unsigned char *p = (unsigned char *) pp; *p++ = (unsigned char) dw; *p++ = (unsigned char)(dw>>=8); *p++ = (unsigned char)(dw>>=8); *p = (unsigned char)(dw>>8); } __inline void la4 (void *p, unsigned long dw) { lw4 (p, lr4 (p) + dw); } void Object::AllocExt (int CurHunk, Import **Imp16, Import **Imp32, Export **Exports) { if (Hunk[CurHunk].nImp16) *Imp16 = Hunk[CurHunk].Imp16 = new Import[Hunk[CurHunk].nImp16]; if (Hunk[CurHunk].nImp32) *Imp32 = Hunk[CurHunk].Imp32 = new Import[Hunk[CurHunk].nImp32]; if (Hunk[CurHunk].nExports) *Exports = Hunk[CurHunk].Exports = new Export[Hunk[CurHunk].nExports]; } #ifdef SUPPORT_AMIGA ObjErr Object::ReadAmiga () { int CurHunk=-1; unsigned long *am = o32, size, *Ext[3]={NULL,NULL,NULL}; bBadExport = true; for (size=Size>>2; size>0; size--) { DWORD n, HunkType = br4(am++); n = br4 (am); switch (HunkType) { default: return OBJERR_HunkType; case HunkUnit: case HunkName: case HunkDbg: size -= ++n; am += n; case HunkEnd: break; case HunkCode: if (CodeHunk >= 0) return OBJERR_NbScns; else { CodeHunk = ++CurHunk; Hunk[CurHunk].size = n << 2; Hunk[CurHunk].o32 = ++am; am += n; size -= n+1; } break; case HunkData: if (DataHunk >= 0) return OBJERR_NbScns; else { DataHunk = ++CurHunk; Hunk[CurHunk].size = n << 2; Hunk[CurHunk].o32 = ++am; am += n; size -= n+1; } break; case HunkBSS: if (BSSHunk >= 0) return OBJERR_NbScns; else Hunk[BSSHunk = ++CurHunk].size = n << 2, am++, size--; break; case HunkR16: fprintf (stderr, "Warning: 16-bit relocations are unsupported.\n"); for (; size>0 && n; n=br4 (am)) n += 2, am += n, size -= n; am++; size--; break; case HunkR32: if (CurHunk < 0) return OBJERR_R32Hunk; else { for (; size>0 && n; n=br4 (am)) { DWORD k = br4 (++am); if (k < 3 && !Hunk[CurHunk].R32[k]) { unsigned long *R32; Hunk[CurHunk].nR32[k] = n; Hunk[CurHunk].R32[k] = R32 = new unsigned long [n]; for (am++; n--; size--) *R32++ = br4 (am++); size -= 2; } else return OBJERR_R32Hunk; } am++; size--; } break; case HunkExt: if (CurHunk < 0 || Ext[CurHunk]) return OBJERR_ExtHunk; else { unsigned char type; unsigned long nExtRefs=0, nImports=0; Ext[CurHunk] = am; do { n = (br4 (am) & 0xFFFFFF) + 1; switch (type = *(unsigned char *)am++) { default: return OBJERR_ExtType; case TypeEnd: break; case TypeImport32: Hunk[CurHunk].nImp32++; case TypeImport16: case TypeImport16Alt: am += n; size -= n; n = br4 (am-1); nImports++; case TypeExport: am += n; size -= n; nExtRefs++; } } while (size-- > 0 && type != TypeEnd); if (!nExtRefs) Ext[CurHunk] = NULL; else { Hunk[CurHunk].nExports = nExtRefs - nImports; Hunk[CurHunk].nImp16 = nImports - Hunk[CurHunk].nImp32; } } } } if (size) return OBJERR_Size; if (CurHunk < 0) return OBJERR_NbScns; nscns = CurHunk+1; for (CurHunk=0; (unsigned int)CurHunkname = (char *)am; am += n; n = br4 (am++); Imp32->nrlcs = n; Imp32->rlc = rlc = new unsigned long [n]; while (n--) *rlc++ = br4 (am++); Imp32++; break; case TypeImport16: case TypeImport16Alt: Imp16->name = (char *)am; am += n; n = br4 (am++); Imp16->nrlcs = n; Imp16->rlc = rlc = new unsigned long [n]; while (n--) *rlc++ = br4 (am++); Imp16++; break; case TypeExport: Exports->name = (char *)am; am += n; //Exports->size = 0; Exports->value = br4 (am++); Exports++; } } } return OBJERR_OK; } #endif char *Object::COFF_ReadName (SYMENT *sym, char *Str) { return br4 (sym->e.e.e_zeroes) ? sym->e.e_name : &Str[br4 (sym->e.e.e_offset)]; } ObjErr Object::ReadCOFF () { int CurHunk=BSSHunk=0; SCNHDR *scn = (SCNHDR *)&o8[sizeof(FILHDR)]; RELOC *Relocs[2]; unsigned short nrlcs[2]; unsigned long i, nSyms, s_vaddr[3]; nscns = br2 (filhdr->f_nscns); if (nscns < 3) return OBJERR_NbScns; if (nscns > 3) { fprintf (stderr, "Warning: More than 3 COFF sections. Excess sections ignored.\n"); nscns = 3; } if (br2 (filhdr->f_opthdr)) return OBJERR_OptHdr; s_vaddr[0] = 0; for (i=0; i= 0) return OBJERR_NbScns; else { Relocs[CurHunk] = (RELOC *)&o8[br4 (scn[i].s_relptr)]; nrlcs[CurHunk] = br2 (scn[i].s_nreloc); Hunk[CodeHunk = ++CurHunk].o8 = &o8[br4 (scn[i].s_scnptr)]; Hunk[CurHunk].size = br4 (scn[i].s_size); s_vaddr[CurHunk] = br4 (scn[i].s_vaddr); } break; case STYP_BSS: // This program can only work properly if the BSS section is the last // one. if (CurHunk != (int) nscns - 1) return OBJERR_NbScns; else { // Objcopy produces real BSS sections, while the GNU assembler // simply leaves an empty section. // Both versions will work here, since the relocs are different // (section 0 (none) vs. section 3). Hunk[0].size = br4 (scn[i].s_size); // This is just a stupid number which has to be subtracted from all // relocs. s_vaddr[0] = br4 (scn[i].s_vaddr); } break; case STYP_DATA: if (DataHunk >= 0) return OBJERR_NbScns; else { Relocs[CurHunk] = (RELOC *)&o8[br4 (scn[i].s_relptr)]; nrlcs[CurHunk] = br2 (scn[i].s_nreloc); Hunk[DataHunk = ++CurHunk].o8 = &o8[br4 (scn[i].s_scnptr)]; Hunk[CurHunk].size = br4 (scn[i].s_size); s_vaddr[CurHunk] = br4 (scn[i].s_vaddr); } break; } SYMENT *sym, *Sym = (SYMENT *)&o8[br4 (filhdr->f_symptr)]; char *Str = (char *)&Sym[nSyms = br4 (filhdr->f_nsyms)]; struct SYMNFO { unsigned char ok; unsigned char R32; unsigned char IsBSSSymbol; unsigned short hunk; struct { unsigned short n16; unsigned short n32; } Hunk[2]; } *SymNfo = (SYMNFO *)_alloca (nSyms*sizeof(SYMNFO)); unsigned long *R32[2][3]; memset (&R32, 0, sizeof (R32)); memset (SymNfo, 0, nSyms*sizeof(SYMNFO)); /************************************\ | Basic symbol and relocation info | \************************************/ // Read in the symbol table and build the SymNfo table with additional // information. // FIXME: Imported symbols shouldn't be considered as exports as well. for (sym=Sym,i=0; ie_sclass)), (long) (short) (br2 (sym->e_scnum)), (long) (br4 (sym->e_value))); #ifdef CHECK_SYMBOLS switch (br2 (sym->e_sclass)) { // All non-standard symbols are not 'ok'. case 0x200: case 0x201: case 0x300: case 0x301: #endif { unsigned int hunk = br2 (sym->e_scnum); if (hunk == nscns) { // It is a symbol in the BSS section, as objcopy produces them. // This program assumes that the BSS section is the last one. // This could be greatly simplified if we assume that there is // always just one single symbol (called '.bss') at the start of // the BSS section. SymNfo[i].IsBSSSymbol = 1; SymNfo[i].R32 = 1; ba4 (sym->e_value, (DWORD)-(long)s_vaddr[0]); } if (hunk >= nscns) hunk = 0; Hunk[SymNfo[i].hunk = hunk].nExports++; SymNfo[i].ok = 1; } #ifdef CHECK_SYMBOLS } #endif } // Here the number of imports and relocations is read in. No relocation is // actually done. for (CurHunk=1; (unsigned int)CurHunkr_symndx); sym = &Sym[i]; if (SymNfo[i].ok) { unsigned long value = br4 (sym->e_value); DEBUG_PRINT ("Reloc %ld: Type 0x%lx; Section %ld; Address 0x%lx\n", (long) (nrlcs[CurHunk-1] - j + 1), (long) (br2 (rlc->r_type)), (long) CurHunk, (long) (long) (br4 (rlc->r_vaddr))); DEBUG_PRINT (" Symbol %ld (%s)\n", (long) i, COFF_ReadName (sym, Str)); switch (br2 (rlc->r_type)) { default: return OBJERR_RlcType; case 0x10: case 0x13: DEBUG_PRINT (" 16-bit reloc\n"); if (!value && !SymNfo[i].hunk) { DEBUG_PRINT (" Normal reloc: Section %ld; Address 0x%lx\n", (long) SymNfo[i].hunk, (long) (br4 (sym->e_value))); if (!SymNfo[i].Hunk[CurHunk-1].n16++) Hunk[CurHunk].nImp16++; } break; case 0x11: case 0x14: // Warning: BSSHunk is 0. // And 0 is also used for imported symbols, which don't have a // section they reside in. // Luckily however, we can decide by looking at the value: // If it's 0, it's an import, like a ROM_CALL or RAM_CALL. // Otherwise, we have a BSS entry. The value then marks the size // of the entry, in bytes. // That means we simply replace the value by an offset into the // BSS section (plus s_vaddr, because COFF requires it). Since // this offset can be 0 for the first symbol in the BSS section, // we sign a special flag. if (SymNfo[i].hunk==0) { DEBUG_PRINT (" Symbol has section 0\n"); DEBUG_PRINT (" Value: %ld (marked as BSS: %ld)\n", (long) value, (long) SymNfo[i].IsBSSSymbol); if (value || SymNfo[i].IsBSSSymbol) { DEBUG_PRINT (" Inserting reloc into BSS section (0)\n"); Hunk[CurHunk].nR32[0]++; if (!SymNfo[i].R32) { unsigned long blocksize = value; SymNfo[i].R32 = 1; SymNfo[i].IsBSSSymbol = 1; bw4 (sym->e_value, value = s_vaddr[0] + Hunk[0].size); Hunk[0].size += blocksize; DEBUG_PRINT (" New BSS size: %ld\n", (long) Hunk[0].size); DEBUG_PRINT (" New value for symbol: %ld\n", (long) value); } } else { DEBUG_PRINT (" Adding import\n"); if (!SymNfo[i].Hunk[CurHunk-1].n32++) Hunk[CurHunk].nImp32++; } } else { DEBUG_PRINT (" Normal reloc: Section %ld; Address 0x%lx\n", (long) SymNfo[i].hunk, (long) (br4 (sym->e_value))); Hunk[CurHunk].nR32[SymNfo[i].hunk]++; SymNfo[i].R32 = 1; } } } else { fprintf (stderr, "Warning: Removing reloc to unsupported symbol '%s'.\n", COFF_ReadName (sym, Str)); } } } /*****************************************************\ | Allocation of export, import, and relocation tables | \*****************************************************/ // All tables are built up using the results from the counting above. Export *Exports[3]={NULL,NULL,NULL}; unsigned long **Imp16rlc[3], **Imp32rlc[3]; for (i=0; iname = COFF_ReadName (sym, Str); Imp16->nrlcs = SymNfo[j].Hunk[i-1].n16; Imp16->rlc = *pImp16rlc++ = new unsigned long [Imp16->nrlcs]; Imp16++; SymNfo[j].Hunk[i-1].n16 = ++n16; } if (SymNfo[j].Hunk[i-1].n32) { Imp32->name = COFF_ReadName (sym, Str); Imp32->nrlcs = SymNfo[j].Hunk[i-1].n32; Imp32->rlc = *pImp32rlc++ = new unsigned long [Imp32->nrlcs]; Imp32++; SymNfo[j].Hunk[i-1].n32 = ++n32; } } // Allocate the relocation tables. for (j=0; jname = COFF_ReadName (sym, Str); Exports[SymNfo[i].hunk]->value = br4 (sym->e_value); Exports[SymNfo[i].hunk]++; } // Initialize import and relocation tables, and relocate. for (CurHunk=1; (unsigned int)CurHunkr_symndx); if (SymNfo[i].ok) { int k; unsigned long ofs; ofs = br4 (rlc->r_vaddr) - s_vaddr[CurHunk]; switch (br2 (rlc->r_type)) { case 0x10: case 0x13: if ((k = SymNfo[i].Hunk[CurHunk-1].n16)) *Imp16rlc[CurHunk][k-1]++ = ofs; break; case 0x11: case 0x14: if (SymNfo[i].R32) { *R32[CurHunk-1][SymNfo[i].hunk]++ = ofs; DEBUG_PRINT ("Relocating 32 bits at offset 0x%lx in section %ld\n", (long) ofs, (long) CurHunk); DEBUG_PRINT (" Old value: 0x%lx\n", (long) br4 (&Hunk[CurHunk].o8[ofs])); ba4 (&Hunk[CurHunk].o8[ofs], (SymNfo[i].IsBSSSymbol ? br4 (Sym[i].e_value) : 0) + ((DWORD)-(long)s_vaddr[SymNfo[i].hunk])); DEBUG_PRINT (" New value: 0x%lx\n", (long) br4 (&Hunk[CurHunk].o8[ofs])); } else if ((k = SymNfo[i].Hunk[CurHunk-1].n32)) *Imp32rlc[CurHunk][k-1]++ = ofs; } } } Delete (Imp16rlc[CurHunk]); Delete (Imp32rlc[CurHunk]); } return OBJERR_OK; } ObjErr Object::Read (char *FileName) { long size = 0; FILE *f = fopen (FileName, "rb"); if (!f) return OBJERR_Open; fseek (f, 0, SEEK_END); Size = ftell (f); rewind (f); if ((o0 = malloc (Size))) size = fread (o0, 1, Size, f); fclose (f); if (!o0) return OBJERR_Mem; if (size != Size) return OBJERR_Read; switch (br2 (o0)) { #ifdef SUPPORT_AMIGA case 0: ObjFmt = OBJFMT_Amiga; return ReadAmiga (); #endif case 0x150: ObjFmt = OBJFMT_COFF; return ReadCOFF (); } return OBJERR_Unknown; } void Object::MergeImp ( unsigned long nImp1, Import * Imp1, unsigned long &nImp2, Import * &Imp2, unsigned long size) { unsigned long n; Import *imp2 = Imp2; for (n=0; nrlc; for (k=imp2->nrlcs; k--; rlc++) *rlc += size; Import *imp1 = Imp1; for (k=nImp1; k--; imp1++) if (!strcmp (imp1->name, imp2->name)) { unsigned long i, j; i = imp1->nrlcs; j = imp2->nrlcs; rlc = new unsigned long [i+j]; memcpy (rlc, imp1->rlc, i * sizeof (long)); memcpy (&rlc[i], imp2->rlc, j * sizeof (long)); Delete (imp1->rlc); Delete (imp2->rlc); imp1->rlc = rlc; imp1->nrlcs += j; if (!--nImp2) Delete (Imp2); else { memmove (imp2, imp2+1, (nImp2-n--) * sizeof (Import)); imp2--; } break; } } } void Object::Merge2 ( unsigned long &n1, void * &p1, unsigned long &n2, void * &p2, unsigned long SizeOf) { if (n2) { unsigned char *p = new unsigned char [(n1+n2)*SizeOf]; memcpy (p, p1, n1 * SizeOf); memcpy (&p[n1*SizeOf], p2, n2 * SizeOf); DeleteCast (unsigned char **, p1); DeleteCast (unsigned char **, p2); n1 += n2; n2 = 0; p1 = p; } } void Object::Merge (int &First, int &Second) { int first, second; if ((unsigned int)(second=Second) < nscns) { if ((unsigned int)(first=First) < nscns) { int hunk; unsigned long size = Hunk[first].size; for (hunk=0; hunk<(int)nscns; hunk++) if (hunk != second) { unsigned long i, *R32 = Hunk[second].R32[hunk]; for (i=Hunk[second].nR32[hunk]; i--; R32++) *R32 += size; } MergeImp ( Hunk[first].nImp16, Hunk[first].Imp16, Hunk[second].nImp16, Hunk[second].Imp16, size); MergeImp ( Hunk[first].nImp32, Hunk[first].Imp32, Hunk[second].nImp32, Hunk[second].Imp32, size); { unsigned long i; Export *exp = Hunk[second].Exports; for (i=Hunk[second].nExports; i--; exp++) exp->value += size; } for (hunk=0; hunk<(int)nscns; hunk++) { unsigned long i, j, *R32_1, *R32_2; i = Hunk[hunk].nR32[first]; j = Hunk[hunk].nR32[second]; Hunk[hunk].nR32[first] += j; Hunk[hunk].nR32[second] = 0; R32_1 = new unsigned long [i+j]; memcpy (R32_1, Hunk[hunk].R32[first], i*sizeof(long)); Delete (Hunk[hunk].R32[first]); Hunk[hunk].R32[first] = R32_1; R32_1 += i; R32_2 = Hunk[hunk].R32[second]; for (; j--; R32_1++) { ba4 (&Hunk[hunk].o8[*R32_1 = *R32_2++], size); if (hunk == second) *R32_1 += size; } Delete (Hunk[hunk].R32[second]); } for (hunk=0; hunk<(int)nscns; hunk++) if (hunk != second) { unsigned long i, j, *R32; i = Hunk[first].nR32[hunk]; j = Hunk[second].nR32[hunk]; Hunk[first].nR32[hunk] += j; Hunk[second].nR32[hunk] = 0; R32 = new unsigned long [i+j]; memcpy (R32, Hunk[first].R32[hunk], i*sizeof(long)); memcpy (&R32[i], Hunk[second].R32[hunk], j*sizeof(long)); Delete (Hunk[first].R32[hunk]); Delete (Hunk[second].R32[hunk]); Hunk[first].R32[hunk] = R32; } Merge2 (Hunk[first].nImp16, (void * &) Hunk[first].Imp16, Hunk[second].nImp16, (void * &) Hunk[second].Imp16, sizeof (Import)); Merge2 (Hunk[first].nImp32, (void * &) Hunk[first].Imp32, Hunk[second].nImp32, (void * &) Hunk[second].Imp32, sizeof (Import)); Merge2 (Hunk[first].nExports, (void * &) Hunk[first].Exports, Hunk[second].nExports, (void * &) Hunk[second].Exports, sizeof (Export)); unsigned size2 = Hunk[second].size; Hunk[first].size += size2; Hunk[second].size = 0; unsigned char *o8 = new unsigned char [size + size2]; memcpy (o8, Hunk[first].o0, size); memcpy (&o8[size], Hunk[second].o0, size2); if (Hunk[second].DelDat) DeleteCast (unsigned char **, Hunk[second].o0); if (Hunk[first].DelDat) DeleteCast (unsigned char **, Hunk[first].o0); else Hunk[first].DelDat = true; Hunk[first].o8 = o8; } else First = second, Second = first; } } #define CONFLICT "%s is incompatible with %s" TI68kErr TI68k::Conflict (TI68kType Type2) { if (szErr) { Delete (szErr[TI68kERR_Conflict-1]); char *msg = szErr[TI68kERR_Conflict-1] = new char [ sizeof(CONFLICT) - 4 + strlen(szTI68kType[Type2-1]) + strlen(szTI68kType[Type-1])]; sprintf (msg, CONFLICT, szTI68kType[Type2-1], szTI68kType[Type-1]); } return TI68kERR_Conflict; } void TI68k::UndefRef (Import *imp) { fprintf (stderr, "Error: %lu undefined reference(s) to '%s'.\n", imp->nrlcs, imp->name); } enum { RAM32, eRAM32, RAM16, eRAM16, ROM, LIBS }; TI68kErr TI68k::MakeDoorsOS () { bool bErr=false; Import *imp; int i, *lens, n16, n32, *ndx, nExtra16=0, nLibs=LIBS, nRAM16=0; n16 = (signed)Hunk[CodeHunk].nImp16; n32 = (signed)Hunk[CodeHunk].nImp32; lens = (int *)_alloca (n32 * sizeof (int)); ndx = (int *)_alloca (n32 * sizeof (int)); for (imp=Hunk[CodeHunk].Imp32,i=0; iname[1], '@'); if ((!p) && ((*imp->name)!='_') && strncmp(imp->name,"L__",3)) { p = strstr (&imp->name[1], "__"); } if (p) { lens[i] = p - imp->name; if (lens[i] > 8 && strncmp (imp->name, "_extraramaddr@", 14)) lens[i] = 0; } else if (!strncmp (imp->name, "_RAM_CALL_", 10) || !strncmp (imp->name, "_ROM_CALL_", 10)) lens[i] = 9; else if (!strncmp (imp->name, "_extraramaddr_", 14)) lens[i] = 13; else lens[i] = 0; if (!lens[i]) UndefRef (imp), bErr = true; else { int j; Import *imp2 = Hunk[CodeHunk].Imp32; for (j=0; jname, imp->name, lens[i])) lens[i] = -lens[i], ndx[i] = ndx[j], j = i; if (j == i) { if (lens[i] <= 8) ndx[i] = nLibs++; else switch (imp->name[2]) { case 'A': ndx[i] = RAM32; break; case 'O': ndx[i] = ROM; break; default: ndx[i] = eRAM32; } } } } for (imp = Hunk[CodeHunk].Imp16,i=0; iname, "_extraramaddr", 13)) nExtra16++; else if (!strncmp (imp->name, "_RAM_CALL_", 10)) nRAM16++; else UndefRef (imp), bErr = true; } if (bErr) return TI68kERR_DoorsOSUndef; struct LibRef { unsigned short ord, nrlcs; unsigned long *rlc; } **Refs = (LibRef **)_alloca (nLibs * sizeof (LibRef *)); struct Lib { char name[9]; unsigned char minVersion /*__attribute__ ((packed))*/; union { unsigned short nRefs; unsigned short nExps; }; union { LibRef *Refs; unsigned short *Exps; }; } Exp, *Libs = (Lib *)_alloca (nLibs * sizeof (Lib)); memset (Libs, 0, nLibs * sizeof (Lib)); Libs[RAM16].nRefs = nRAM16; Libs[eRAM16].nRefs = nExtra16; struct { unsigned short code, comment, main, exit, extra; } Ofs = { 0, 0, 0, 0, 0}; unsigned short HeaderSize = 40 + (nLibs-LIBS) * 12 + 2 * (unsigned short)(Hunk[CodeHunk].nR32[CodeHunk] + Hunk[CodeHunk].nR32[BSSHunk]); if (!(Hunk[BSSHunk].size)) HeaderSize-=6; for (imp=Hunk[CodeHunk].Imp32,i=0; i 0 && ndx[i] >= LIBS) strncpy (Libs[ndx[i]].name, imp->name, lens[i]); Libs[ndx[i]].nRefs++; } if (Libs[ROM].nRefs) HeaderSize += 2; if (Libs[RAM32].nRefs || Libs[eRAM32].nRefs || Libs[RAM16].nRefs || Libs[eRAM16].nRefs) HeaderSize += 2; for (i=0; iord = (unsigned short) strtoul (&imp->name[abs(lens[i])+(((imp->name[abs(lens[i])]=='_')&&(imp->name[abs(lens[i])+1]=='_'))?2:1)], &p, 16); HeaderSize += ((*refs)->nrlcs = (unsigned short) imp->nrlcs) * 2; (*refs)->rlc = imp->rlc; (*refs)++; } nRAM16 = nExtra16 = 0; for (imp = Hunk[CodeHunk].Imp16,i=0; iname, "_RAM_CALL_", 10)) len = 10, refs = &Libs[RAM16].Refs[nRAM16++]; else len = 14, refs = &Libs[eRAM16].Refs[nExtra16++]; refs->ord = (unsigned short)strtoul (&imp->name[len], &p, 16); if (*p) UndefRef (imp), bErr = true; HeaderSize += (refs->nrlcs = (unsigned short) imp->nrlcs) * 2; refs->rlc = imp->rlc; } if (bErr) return TI68kERR_DoorsOSUndef; Export *exp = Hunk[CodeHunk].Exports; Exp.nRefs = 0; for (i=(int)Hunk[CodeHunk].nExports; i--; exp++) { if (!strcmp (exp->name, "_comment")) Ofs.comment = (unsigned short)exp->value; else if (!strcmp (exp->name, "_main")) Ofs.main = (unsigned short)exp->value; else if (!strcmp (exp->name, "_exit")) Ofs.exit = (unsigned short)exp->value; else if (!strcmp (exp->name, "_extraram")) Ofs.extra = (unsigned short)exp->value; else { char *p = strrchr (&exp->name[1], '@'); if ((!p) && ((*exp->name)!='_') && strncmp(exp->name,"L__",3)) { p = strstr (&exp->name[1], "__"); } if (p) { if (!strncmp(p+((*p=='_')?2:1),"version",7)) { int len = p - exp->name; if (len > 8) return TI68kERR_BadExport; unsigned long j = strtoul (p+((*p=='_')?9:8), &p, 16); if ((*p) || (j > 255ul)) return TI68kERR_BadExport; else { for (int ii=0; iiname,len)) Libs[ii].minVersion=j; } }} else { int len = p - exp->name; if (len > 8) return TI68kERR_BadExport; if (!Exp.nRefs) { strncpy (Exp.name, exp->name, len); Exp.name[len] = 0; } else if (strncmp (Exp.name, exp->name, len)) return TI68kERR_BadExport; Exp.nRefs++; } } } } if (Exp.nRefs) { HeaderSize += 4 + 2 * Exp.nRefs; Exp.Refs = (LibRef *)_alloca (Exp.nRefs * sizeof (short)); memset (Exp.Refs, -1, Exp.nRefs * sizeof (short)); exp = Hunk[CodeHunk].Exports; for (i=(int)Hunk[CodeHunk].nExports; i--; exp++) { char *p = strrchr (&exp->name[1], '@'); if ((!p) && ((*exp->name)!='_') && strncmp(exp->name,"L__",3)) { p = strstr (&exp->name[1], "__"); if (p) p++; } if (p++) { if (strncmp(p,"version",7)) { unsigned long j = strtoul (p, &p, 16); if (*p || j >= Exp.nExps || (short)Exp.Exps[j] != -1) return TI68kERR_BadExport; Exp.Exps[j] = (unsigned short)exp->value; } } } } union { void *o0; unsigned char *o8; unsigned short *o16; unsigned long *o32; }; Ofs.code = HeaderSize + (Type == TI68k_68kP ? sizeof (PrgmStub) : sizeof (LibStub)); o8 = dat = new unsigned char [size = Ofs.code + Hunk[CodeHunk].size + 3]; bw2 (o16++, 0x6100); bw2 (o16++, HeaderSize-2); bw4 (o32++, ('6'<<24)+('8'<<16)+('k'<<8)+(Type==TI68k_68kP?'P':'L')); *o16++ = 0; bw2 (o16++, Ofs.comment ? Ofs.comment + Ofs.code : 0); bw2 (o16++, Type == TI68k_68kP ? Ofs.main + Ofs.code : 0); bw2 (o16++, Ofs.exit ? Ofs.exit + Ofs.code : 0); bw2 (o16++, Flags); *o16++ = 0; *o32++ = 0; bw2 (o16++, Ofs.extra ? Ofs.extra + Ofs.code : 0); bw2 (o16++, nLibs-LIBS); for (i=LIBS; iord); unsigned long *rlc = Refs->rlc; unsigned short k=Refs++->nrlcs; while (k--) bw2 (o16++, Ofs.code + (unsigned short)*rlc++); *o16++ = 0; } while (j--); } if (!Libs[ROM].nRefs) *o16++ = 0; else { bw2 (o16++, (unsigned short)-1); int j = Libs[ROM].nRefs; bw2 (o16++, --j); LibRef *Refs = Libs[ROM].Refs; do { bw2 (o16++, Refs->ord); unsigned long *rlc = Refs->rlc; unsigned short k=Refs++->nrlcs; while (k--) bw2 (o16++, Ofs.code + (unsigned short)*rlc++); *o16++ = 0; } while (j--); } i = Libs[RAM32].nRefs + Libs[eRAM32].nRefs + Libs[RAM16].nRefs + Libs[eRAM16].nRefs; if (!i--) *o16++ = 0; else { bw2 (o16++, (unsigned short)-1); bw2 (o16++, i); for (i=RAM32; i<=eRAM16; i++) { int j; LibRef *Refs = Libs[i].Refs; for (j=Libs[i].nRefs; j; j--) { bw2 (o16++, Refs->ord + (unsigned short)(i<<14)); unsigned long *rlc = Refs->rlc; unsigned short k=Refs++->nrlcs; while (k--) bw2 (o16++, Ofs.code + (unsigned short)*rlc++); *o16++ = 0; } } } unsigned long *R32 = Hunk[CodeHunk].R32[CodeHunk]; for (i=(int)Hunk[CodeHunk].nR32[CodeHunk]; i; i--) bw2 (o16++, Ofs.code + (unsigned short)*R32++); *o16++ = 0; if (Hunk[BSSHunk].size) { bw2 (&dat[0x14], (unsigned short)(o8-dat)); bw4 (o32++, Hunk[BSSHunk].size); R32 = Hunk[CodeHunk].R32[BSSHunk]; for (i=(int)Hunk[CodeHunk].nR32[BSSHunk]; i; i--) bw2 (o16++, Ofs.code + (unsigned short)*R32++); *o16++ = 0; } else bw2 (&dat[0x14], (unsigned short)0); if (Exp.nRefs) { bw2 (&dat[0x16], (unsigned short)(o8-dat)); bw2 (o16++, Exp.nRefs); for (i=0; i= 0) if (Hunk[BSSHunk].size) { Hunk[BSSHunk].o8 = new unsigned char [Hunk[BSSHunk].size]; Hunk[BSSHunk].DelDat = true; memset (Hunk[BSSHunk].o8, 0, Hunk[BSSHunk].size); Merge (CodeHunk, BSSHunk); } if (!NostubImp (Hunk[CodeHunk].nImp16, Hunk[CodeHunk].Imp16) && !NostubImp (Hunk[CodeHunk].nImp32, Hunk[CodeHunk].Imp32)) { unsigned long n = Hunk[CodeHunk].nR32[CodeHunk]; unsigned long *R32 = Hunk[CodeHunk].R32[CodeHunk]; size = Hunk[CodeHunk].size + 4 * n + 3; dat = new unsigned char [size]; memcpy (dat, Hunk[CodeHunk].o0, Hunk[CodeHunk].size); unsigned short *o16 = (unsigned short *)&dat[size-1]; *(unsigned char *)o16-- = 0xF3; for (; n--; R32++) { bw2 (o16--, (unsigned short)*R32); bw2 (o16--, (unsigned short)br4 (&dat[*R32])); } *o16 = 0; return TI68kERR_OK; } else return TI68kERR_NostubUndef; } bool TI68k::ExtImp (unsigned long n, Import *imp) { if (!n) return false; for (; n--; imp++) UndefRef (imp); return true; } char *OutputName2=0; bool InList(char *str, char *list) { if (!*list) return true; while (*list) if (!strcmp(str,list)) return true; else while (*list++); return false; } void maj_conv(char *s) { char c; while ((c=*s++)) if (c>='A' && c<='Z') memmove(s+1,s,strlen(s)+1), *s='-'; } TI68kErr TI68k::MakeExt () { /* TODO (?) : BSS aren't supported */ if (BSSHunk >= 0) if (Hunk[BSSHunk].size) { Hunk[BSSHunk].o8 = new unsigned char [Hunk[BSSHunk].size]; Hunk[BSSHunk].DelDat = true; memset (Hunk[BSSHunk].o8, 0, Hunk[BSSHunk].size); Merge (CodeHunk, BSSHunk); } char *ExportList; FILE *ex_fp=fopen("export.dat","rb"); if (!ex_fp) ExportList=""; else ExportList = new char [300000], fread(ExportList,300000,1,ex_fp), fclose(ex_fp); FILE *def_fp=fopen("deflt.txt","a+"); unsigned long nExp = 0, szExpN = 0; int n=Hunk[CodeHunk].nExports; Export *exp = Hunk[CodeHunk].Exports; unsigned long *expOffs = new unsigned long [n]; char **expName = new char * [n]; for (; n--; exp++) { if (InList(exp->name, ExportList)) { char buf[200]; sprintf(buf,"%s.ref",exp->name); maj_conv(buf); FILE *fp=fopen(buf,"w"); if (!fp) { printf("Couldn't open '%s' !\n",buf); return TI68kERR_Unknown; } sprintf(buf,"%s.ext",OutputName2); fputs(buf,fp); fclose(fp); if (def_fp) fprintf(def_fp,"#var %s\n",exp->name); expOffs[nExp] = exp->value, expName[nExp] = exp->name, szExpN += strlen(exp->name)+1, nExp++; } } if (def_fp) fclose(def_fp); unsigned long nRef0 = 0, nRef = 0, nImp = 0, szImpN = 0; int i; int n32=Hunk[CodeHunk].nImp32, n16=Hunk[CodeHunk].nImp16; Import *imp32 = Hunk[CodeHunk].Imp32, *imp16 = Hunk[CodeHunk].Imp16, *imp; for (n=n16,imp=imp16; n--; imp++) nRef0+=imp->nrlcs+1; for (n=n32,imp=imp32; n--; imp++) nRef0+=imp->nrlcs+1; unsigned long *impOffs = new unsigned long [nRef0]; char **impName = new char * [n16+n32]; for (n=n16,imp=imp16; n--; imp++) { for (i=imp->nrlcs;i--;) impOffs[nRef] = imp->rlc[i]-2, nRef++; impOffs[nRef] = -2ul, nRef++; impName[nImp] = imp->name, szImpN += strlen(imp->name)+1, nImp++; } for (n=n32,imp=imp32; n--; imp++) { for (i=imp->nrlcs;i--;) impOffs[nRef] = imp->rlc[i], nRef++; impOffs[nRef] = -2ul, nRef++; impName[nImp] = imp->name, szImpN += strlen(imp->name)+1, nImp++; } unsigned long nInt = Hunk[CodeHunk].nR32[CodeHunk]; unsigned long *R32 = Hunk[CodeHunk].R32[CodeHunk]; size = (2+Hunk[CodeHunk].size) + (2*nInt+2) + (2*nExp+2+szExpN) + (szExpN&1) + (2*nRef+2+szImpN) + (szImpN&1) + (2); dat = new unsigned char [size]; memset (dat, 0, size); unsigned char *p8 = dat; #define w16(x) (bw2(p8,(unsigned short)(x)), p8+=2) w16(2+Hunk[CodeHunk].size); memcpy (p8, Hunk[CodeHunk].o0, Hunk[CodeHunk].size), p8+=Hunk[CodeHunk].size; /* Relocation section */ for (n=nInt; n--; R32++) { w16(2+(unsigned short)*R32); } w16(0); /* Export section */ for (n=nExp;n--;) w16(2+expOffs[n]); w16(0); for (n=nExp;n--;) strcpy((char *)p8, expName[n]), p8+=strlen(expName[n])+1; if (szExpN&1) *p8++=0; /* Import section */ for (i=0;i<(int)nRef;i++) w16(2+impOffs[i]); w16(0); for (i=0;i<(int)nImp;i++) strcpy((char *)p8, impName[i]), p8+=strlen(impName[i])+1; if (szImpN&1) *p8++=0; /* BSS section */ w16(0); #ifndef NDEBUG if (p8!=&dat[size]) { printf("Size mismatch!\n"); return TI68kERR_Unknown; } #endif return TI68kERR_OK; } TI68kErr TI68k::Make () { int hunk; for (hunk=0; hunk<3; hunk++) { unsigned long i; Export *exp = Hunk[hunk].Exports; for (i=Hunk[hunk].nExports; i; exp++,i--) { if (!strcmp (exp->name, szTI68kType[TI68k_68kL-1])) { if (Type == TI68k_none) Type = TI68k_68kL; else return Conflict (TI68k_68kL); } else if (!strcmp (exp->name, szTI68kType[TI68k_68kP-1])) { if (Type == TI68k_none) Type = TI68k_68kP; else if (Type != TI68k_nostub) return Conflict (TI68k_68kP); } else if (!strcmp (exp->name, szTI68kType[TI68k_ext-1])) { if (Type == TI68k_none) Type = TI68k_ext; else return Conflict (TI68k_ext); } else if (!strcmp (exp->name, szTI68kType[TI68k_nostub-1])) { if (Type == TI68k_none || Type == TI68k_68kP) Type = TI68k_nostub; else if (Type != TI68k_nostub_dll) return Conflict (TI68k_nostub); } else if (!strcmp (exp->name, szTI68kType[TI68k_nostub_dll-1])) { if (Type == TI68k_none || Type == TI68k_68kP || Type == TI68k_nostub) Type = TI68k_nostub_dll; else return Conflict (TI68k_nostub_dll); } else if (!strcmp (exp->name, szTI68kType[TI68k_prosit-1])) return TI68kERR_prosit; else if (!strcmp (exp->name, "_ti89")) Output89 = 1; else if (!strcmp(exp->name, "_ti92plus")) Output92p = 1; else if (!strncmp(exp->name, "_flag_", 6)) Flags |= 1 << strtoul (&exp->name[6], NULL, 10); else if (!strncmp(exp->name, "_version", 6)) LibVersion = strtoul (&exp->name[8], NULL, 16); else if (bBadExport && strcmp (exp->name, "_comment") && strcmp (exp->name, "_exit") && strcmp (exp->name, "_extraram")) { char *p = strrchr (&exp->name[1], '@'); if (p) if (p[1]) { strtoul (&p[1], &p, 16); if (*p) p = NULL; } if (!p) return TI68kERR_BadExport; } } } if (!Output89 && !Output92p && Type!=TI68k_ext) return TI68kERR_NoOutput; Merge (CodeHunk, DataHunk); switch (Type) { case TI68k_ext: return MakeExt (); case TI68k_nostub: case TI68k_nostub_dll: return MakeNostub (); default: return MakeDoorsOS (); } return TI68kERR_Unknown; } TI68kErr TI68k::DoSave (char *FileName, char *ext, char *Header, unsigned long HeaderSize, unsigned short chksum) { if (strlen (FileName) + strlen (ext) < _MAX_PATH) { unsigned char buf[2]; char FullName[_MAX_PATH]; FILE *f; f = fopen (strcat (strcpy (FullName, FileName), ext), "wb"); if (HeaderSize) fwrite (Header, 1, HeaderSize, f); bw2 (buf, (unsigned short)size); fwrite (buf, 1, 2, f); fwrite (dat, 1, size, f); if (HeaderSize) lw2 (buf, chksum), fwrite (buf, 1, 2, f); fclose (f); } return TI68kERR_OK; } TI68kErr TI68k::Save (char *FileName, bool outputbin, bool quiet) { static char Header[]= "**TI92P*\001\0main\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\001\0R\0\0\0\0\0\0\0\0\0\0\0!\0\0\0\0\0\0\0ĄZ\0\0\0"; #define HeaderSize (sizeof (Header)) char AMSname[9], *p; unsigned short chksum; if (GetExeSize () > MAX_VAR_SIZE) return TI68kERR_TooLarge; AMSname[8] = 0; p = strrchr (FileName, '\\'); _strlwr (strncpy (AMSname, p ? p + 1 : FileName, 8)); strncpy (&Header[0x40], AMSname, 8); lw4 (&Header[0x4C], size + HeaderSize + 4); if (outputbin || Type == TI68k_nostub_dll || Type == TI68k_ext) { if (Type == TI68k_nostub_dll && !outputbin) DoSave (FileName, ".ndl", NULL, 0, 0); else if (Type == TI68k_ext && !outputbin) DoSave (FileName, ".ext", NULL, 0, 0); else DoSave (FileName, ".bin", NULL, 0, 0); if (!quiet) { if (Output89) printf ("Linked for TI-89\n"); if (Output92p) printf ("Linked for TI-92 Plus\n"); } } else { chksum = LOBYTE (size) + HIBYTE (size); unsigned long i; for (i=0; i\n" "Modified by: Romain Lievin \n" " Sebastian Reichelt \n" " Kevin Kofler \n" " and Paul Froissart\n" ); if (help) puts ( "Usage: obj2ti [options] file\n" "Options:\n" " -h --help\tDisplay this information\n" " -o --output\tFollowed by project name\n" " -O --outputbin\tOutput a binary file, not a calc file\n" " -q --quiet\tLink without displaying extra verbose information\n" " -v --version\tDisplay program version number\n" " -x --ext\tOutput a .ext object suitable for GTC\n" ); else if (ObjFile) { TI68k *ti = new TI68k (szErr, Type); err = ti->Read (ObjFile); if (!err) { char *ext = strrchr (OutputName2 = ObjFile, '.'); if (ext && (!strcmp(ext,".o") || !strcmp(ext,".O"))) *ext = 0; err = ti->Make (); if (!err) { if (!OutputName) { char *ext = strrchr (OutputName = ObjFile, '.'); if (ext) if (!_stricmp (ext, ".o")) *ext = 0; } err = ti->Save (OutputName, outputbin, quiet); if (!err && !quiet) printf ("Linked %s - Size: %lu bytes\n", OutputName, ti->GetExeSize ()); } } if (err) { if (err == TI68kERR_TooLarge) fprintf (stderr, "Error: Size of %lu bytes exceeds maximum by %lu.\n", ti->GetExeSize (), ti->GetExeSize () - MAX_VAR_SIZE); else if (szErr[err-1]) fprintf (stderr, "%s.\n", szErr[err-1]); } delete ti; } return err; }