mirror of https://git.wuffs.org/MWCC
924 lines
30 KiB
C
924 lines
30 KiB
C
#include "compiler/MachO.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/CPrep.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/ObjGenMachO.h"
|
|
#include "cos.h"
|
|
|
|
static MachOSegment *FirstSeg;
|
|
static MachOSegment *LastSeg;
|
|
static UInt32 SectNum;
|
|
static UInt32 SymNum;
|
|
static UInt32 NumStabs;
|
|
static UInt32 ilocalsym;
|
|
static UInt32 nlocalsym;
|
|
static UInt32 iextdefsym;
|
|
static UInt32 nextdefsym;
|
|
static UInt32 iundefsym;
|
|
static UInt32 nundefsym;
|
|
static MachOSymbol *FirstSym;
|
|
static MachOSymbol *LastSym;
|
|
static MachOSymbol *FirstStab;
|
|
static MachOSymbol *LastStab;
|
|
static UInt32 FileOffset;
|
|
static UInt32 VmAddr;
|
|
static GList ObjFile;
|
|
static SInt32 SymPad;
|
|
static UInt32 CodeSize;
|
|
static UInt32 IdataSize;
|
|
static UInt32 UdataSize;
|
|
static GList IndirectSymbolTable;
|
|
static GList StringTable;
|
|
static UInt32 IndirectSymbolTableOffset;
|
|
|
|
void MachO_Setup(void) {
|
|
FirstSeg = LastSeg = NULL;
|
|
FirstSym = LastSym = NULL;
|
|
FirstStab = LastStab = NULL;
|
|
|
|
SectNum = 0;
|
|
SymNum = 0;
|
|
NumStabs = 0;
|
|
|
|
ilocalsym = -1;
|
|
nlocalsym = 0;
|
|
|
|
iextdefsym = -1;
|
|
nextdefsym = 0;
|
|
|
|
iundefsym = -1;
|
|
nundefsym = 0;
|
|
|
|
InitGList(&IndirectSymbolTable, 256);
|
|
InitGList(&StringTable, 4096);
|
|
AppendGListByte(&StringTable, 0);
|
|
}
|
|
|
|
static UInt32 GetSectVMAddr(UInt32 id) {
|
|
MachOSegment *segment;
|
|
MachOSection *section;
|
|
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
for (section = segment->firstSection; section; section = section->next) {
|
|
if (section->num == id)
|
|
return section->section.addr;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static UInt32 AllocateForLoadCommands(void) {
|
|
UInt32 ncmds = 0;
|
|
MachOSegment *segment;
|
|
MachOSection *section;
|
|
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
FileOffset += sizeof(struct segment_command);
|
|
segment->cmd.cmdsize += sizeof(struct segment_command);
|
|
ncmds++;
|
|
|
|
for (section = segment->firstSection; section; section = section->next) {
|
|
segment->cmd.cmdsize += sizeof(struct section);
|
|
FileOffset += sizeof(struct section);
|
|
}
|
|
}
|
|
|
|
return ncmds;
|
|
}
|
|
|
|
static UInt32 AlignModulus[] = {
|
|
1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800
|
|
};
|
|
|
|
static void AllocateAddresses(void) {
|
|
MachOSegment *segment;
|
|
MachOSection *section;
|
|
UInt32 pad;
|
|
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
segment->cmd.vmaddr = VmAddr;
|
|
segment->cmd.fileoff = FileOffset;
|
|
|
|
for (section = segment->firstSection; section; section = section->next) {
|
|
if (section->glist.size)
|
|
section->section.size = section->glist.size;
|
|
|
|
pad = AlignModulus[section->section.align] - (VmAddr % AlignModulus[section->section.align]);
|
|
pad %= AlignModulus[section->section.align];
|
|
|
|
VmAddr += pad;
|
|
section->section.addr = VmAddr;
|
|
VmAddr += section->section.size;
|
|
|
|
FileOffset += pad;
|
|
if (section->glist.size) {
|
|
section->section.offset = FileOffset;
|
|
FileOffset += section->glist.size;
|
|
} else {
|
|
section->section.offset = FileOffset;
|
|
}
|
|
|
|
if (!strncmp(section->section.segname, "__TEXT", 6)) {
|
|
CodeSize += section->section.size;
|
|
} else {
|
|
if (section->glist.size)
|
|
IdataSize += section->section.size;
|
|
else
|
|
UdataSize += section->section.size;
|
|
}
|
|
}
|
|
|
|
segment->cmd.filesize = FileOffset - segment->cmd.fileoff;
|
|
segment->cmd.vmsize = VmAddr - segment->cmd.vmaddr;
|
|
}
|
|
}
|
|
|
|
static void ApplyRelocs(void) {
|
|
MachOSegment *segment;
|
|
MachOSection *section;
|
|
MachOReloc *reloc;
|
|
enum reloc_type_ppc pairType;
|
|
UInt32 pairValue;
|
|
UInt32 opMask;
|
|
UInt32 argMask;
|
|
UInt32 value;
|
|
UInt32 *ptr;
|
|
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
for (section = segment->firstSection; section; section = section->next) {
|
|
for (reloc = section->firstReloc; reloc; reloc = reloc->next) {
|
|
if (reloc->is_extern) {
|
|
opMask = 0xFFFFFFFF;
|
|
argMask = 0;
|
|
value = 0;
|
|
switch (reloc->reltype) {
|
|
case PPC_RELOC_HI16:
|
|
case PPC_RELOC_LO16:
|
|
case PPC_RELOC_HA16:
|
|
pairValue = 0;
|
|
pairType = reloc->reltype;
|
|
break;
|
|
}
|
|
} else if (reloc->reltype == PPC_RELOC_PAIR) {
|
|
if (reloc->value != 0xFFFFFF) {
|
|
value = pairValue - (reloc->value + section->section.addr);
|
|
value += reloc->address;
|
|
} else {
|
|
value = pairValue + reloc->address;
|
|
}
|
|
switch (pairType) {
|
|
case PPC_RELOC_HI16:
|
|
opMask = 0xFFFF0000;
|
|
argMask = 0xFFFF;
|
|
value >>= 16;
|
|
break;
|
|
case PPC_RELOC_HA16:
|
|
opMask = 0xFFFF0000;
|
|
argMask = 0xFFFF;
|
|
if (value & 0x8000)
|
|
value += 0x10000;
|
|
value >>= 16;
|
|
break;
|
|
case PPC_RELOC_LO16:
|
|
opMask = 0xFFFF0000;
|
|
argMask = 0xFFFF;
|
|
value = value & 0xFFFF;
|
|
break;
|
|
case PPC_RELOC_HI16_SECTDIFF:
|
|
opMask = 0xFFFF0000;
|
|
argMask = 0xFFFF;
|
|
value >>= 16;
|
|
break;
|
|
case PPC_RELOC_HA16_SECTDIFF:
|
|
opMask = 0xFFFF0000;
|
|
argMask = 0xFFFF;
|
|
if (value & 0x8000)
|
|
value += 0x10000;
|
|
value >>= 16;
|
|
break;
|
|
case PPC_RELOC_LO16_SECTDIFF:
|
|
opMask = 0xFFFF0000;
|
|
argMask = 0xFFFF;
|
|
value = value & 0xFFFF;
|
|
break;
|
|
case PPC_RELOC_SECTDIFF:
|
|
opMask = 0;
|
|
argMask = 0xFFFFFFFF;
|
|
break;
|
|
default:
|
|
CError_FATAL(388);
|
|
}
|
|
} else {
|
|
value = GetSectVMAddr(reloc->value);
|
|
switch (reloc->reltype) {
|
|
case PPC_RELOC_VANILLA:
|
|
opMask = 0;
|
|
argMask = 0xFFFFFFFF;
|
|
break;
|
|
case PPC_RELOC_BR14:
|
|
opMask = 0xFFFF0003;
|
|
argMask = 0xFFFC;
|
|
break;
|
|
case PPC_RELOC_BR24:
|
|
opMask = 0xFC000003;
|
|
argMask = 0x3FFFFFC;
|
|
break;
|
|
case PPC_RELOC_LO14:
|
|
opMask = 0xFFFF0003;
|
|
argMask = 0xFFFC;
|
|
break;
|
|
case PPC_RELOC_HI16:
|
|
case PPC_RELOC_HA16:
|
|
case PPC_RELOC_LO16:
|
|
case PPC_RELOC_HI16_SECTDIFF:
|
|
case PPC_RELOC_HA16_SECTDIFF:
|
|
case PPC_RELOC_LO16_SECTDIFF:
|
|
case PPC_RELOC_SECTDIFF:
|
|
// first half of a pair
|
|
opMask = 0xFFFF0000;
|
|
argMask = 0xFFFF;
|
|
pairValue = value;
|
|
pairType = reloc->reltype;
|
|
value = 0;
|
|
break;
|
|
case PPC_RELOC_PB_LA_PTR:
|
|
CError_FATAL(428);
|
|
break;
|
|
default:
|
|
CError_FATAL(432);
|
|
}
|
|
}
|
|
|
|
if (reloc->reltype != PPC_RELOC_PAIR)
|
|
ptr = (UInt32 *) ((*section->glist.data) + reloc->address);
|
|
|
|
if (reloc->is_pcrel) {
|
|
if (!reloc->is_extern) {
|
|
*ptr = CTool_EndianConvertWord32(
|
|
(CTool_EndianConvertWord32(*ptr) & opMask) |
|
|
(argMask & (value - (reloc->address + section->section.addr) + (CTool_EndianConvertWord32(*ptr) & argMask))));
|
|
}
|
|
} else {
|
|
if (reloc->reltype == PPC_RELOC_PAIR) {
|
|
*ptr = CTool_EndianConvertWord32(
|
|
(CTool_EndianConvertWord32(*ptr) & opMask) |
|
|
(value & argMask)
|
|
);
|
|
} else {
|
|
*ptr = CTool_EndianConvertWord32(
|
|
(CTool_EndianConvertWord32(*ptr) & opMask) |
|
|
(argMask & (value + (CTool_EndianConvertWord32(*ptr) & argMask)))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void AllocForRelocs(void) {
|
|
MachOSegment *segment;
|
|
MachOSection *section;
|
|
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
for (section = segment->firstSection; section; section = section->next) {
|
|
if (section->section.nreloc) {
|
|
section->section.reloff = FileOffset;
|
|
FileOffset += section->section.nreloc * 8;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void WriteSegLoadCommands(void) {
|
|
MachOSegment *segment;
|
|
MachOSection *section;
|
|
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
#ifdef ENDIAN_CONVERSION
|
|
struct segment_command c = segment->cmd;
|
|
c.cmd = CTool_EndianConvertWord32(c.cmd);
|
|
c.cmdsize = CTool_EndianConvertWord32(c.cmdsize);
|
|
c.vmaddr = CTool_EndianConvertWord32(c.vmaddr);
|
|
c.vmsize = CTool_EndianConvertWord32(c.vmsize);
|
|
c.fileoff = CTool_EndianConvertWord32(c.fileoff);
|
|
c.filesize = CTool_EndianConvertWord32(c.filesize);
|
|
c.maxprot = CTool_EndianConvertWord32(c.maxprot);
|
|
c.initprot = CTool_EndianConvertWord32(c.initprot);
|
|
c.nsects = CTool_EndianConvertWord32(c.nsects);
|
|
c.flags = CTool_EndianConvertWord32(c.flags);
|
|
AppendGListData(&ObjFile, &c, sizeof(c));
|
|
#else
|
|
AppendGListData(&ObjFile, &segment->cmd, sizeof(segment->cmd));
|
|
#endif
|
|
|
|
for (section = segment->firstSection; section; section = section->next) {
|
|
#ifdef ENDIAN_CONVERSION
|
|
struct section c = section->section;
|
|
c.addr = CTool_EndianConvertWord32(c.addr);
|
|
c.size = CTool_EndianConvertWord32(c.size);
|
|
c.offset = CTool_EndianConvertWord32(c.offset);
|
|
c.align = CTool_EndianConvertWord32(c.align);
|
|
c.reloff = CTool_EndianConvertWord32(c.reloff);
|
|
c.nreloc = CTool_EndianConvertWord32(c.nreloc);
|
|
c.flags = CTool_EndianConvertWord32(c.flags);
|
|
c.reserved1 = CTool_EndianConvertWord32(c.reserved1);
|
|
c.reserved2 = CTool_EndianConvertWord32(c.reserved2);
|
|
|
|
AppendGListData(&ObjFile, &c, sizeof(c));
|
|
#else
|
|
AppendGListData(&ObjFile, §ion->section, sizeof(section->section));
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static void WriteSymtabLoadCommand(void) {
|
|
struct symtab_command cmd;
|
|
UInt32 total;
|
|
|
|
cmd.cmd = CTool_EndianConvertWord32(LC_SYMTAB);
|
|
cmd.cmdsize = CTool_EndianConvertWord32(sizeof(cmd));
|
|
cmd.symoff = CTool_EndianConvertWord32(FileOffset);
|
|
total = SymNum + NumStabs;
|
|
cmd.nsyms = total;
|
|
FileOffset += total * sizeof(struct nlist);
|
|
cmd.stroff = CTool_EndianConvertWord32(FileOffset);
|
|
cmd.strsize = CTool_EndianConvertWord32(StringTable.size);
|
|
|
|
AppendGListData(&ObjFile, &cmd, sizeof(cmd));
|
|
}
|
|
|
|
static void WriteDynamicSymtabLoadCommand(void) {
|
|
struct dysymtab_command cmd;
|
|
|
|
if (!nlocalsym)
|
|
ilocalsym = 0;
|
|
if (!nextdefsym)
|
|
iextdefsym = ilocalsym + nlocalsym;
|
|
if (!nundefsym)
|
|
iundefsym = iextdefsym + nextdefsym;
|
|
|
|
ilocalsym += NumStabs;
|
|
iextdefsym += NumStabs;
|
|
iundefsym += NumStabs;
|
|
|
|
CError_ASSERT(644, (ilocalsym + nlocalsym) <= (SymNum + NumStabs));
|
|
|
|
CError_ASSERT(648, (iextdefsym + nextdefsym) <= (SymNum + NumStabs));
|
|
|
|
CError_ASSERT(652, (iundefsym + nundefsym) <= (SymNum + NumStabs));
|
|
|
|
cmd.cmd = CTool_EndianConvertWord32(LC_DYSYMTAB);
|
|
cmd.cmdsize = CTool_EndianConvertWord32(sizeof(cmd));
|
|
|
|
cmd.ilocalsym = CTool_EndianConvertWord32(ilocalsym);
|
|
cmd.nlocalsym = CTool_EndianConvertWord32(nlocalsym);
|
|
cmd.iextdefsym = CTool_EndianConvertWord32(iextdefsym);
|
|
cmd.nextdefsym = CTool_EndianConvertWord32(nextdefsym);
|
|
cmd.iundefsym = CTool_EndianConvertWord32(iundefsym);
|
|
cmd.nundefsym = CTool_EndianConvertWord32(nundefsym);
|
|
|
|
cmd.tocoff = 0;
|
|
cmd.ntoc = 0;
|
|
cmd.modtaboff = 0;
|
|
cmd.nmodtab = 0;
|
|
cmd.extrefsymoff = 0;
|
|
cmd.nextrefsyms = 0;
|
|
cmd.indirectsymoff = CTool_EndianConvertWord32(IndirectSymbolTableOffset);
|
|
cmd.nindirectsyms = CTool_EndianConvertWord32(IndirectSymbolTable.size / 4);
|
|
cmd.extreloff = 0;
|
|
cmd.nextrel = 0;
|
|
cmd.locreloff = 0;
|
|
cmd.nlocrel = 0;
|
|
|
|
AppendGListData(&ObjFile, &cmd, sizeof(cmd));
|
|
}
|
|
|
|
static void WriteSectionData(void) {
|
|
MachOSegment *segment;
|
|
MachOSection *section;
|
|
UInt32 pad;
|
|
|
|
VmAddr = 0;
|
|
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
for (section = segment->firstSection; section; section = section->next) {
|
|
pad = AlignModulus[section->section.align] - (VmAddr % AlignModulus[section->section.align]);
|
|
pad %= AlignModulus[section->section.align];
|
|
|
|
while (pad) {
|
|
AppendGListByte(&ObjFile, 0);
|
|
VmAddr++;
|
|
FileOffset++;
|
|
pad--;
|
|
}
|
|
|
|
if (section->glist.size) {
|
|
CError_ASSERT(711, ObjFile.size == section->section.offset);
|
|
|
|
COS_LockHandle(section->glist.data);
|
|
AppendGListData(&ObjFile, *section->glist.data, section->glist.size);
|
|
COS_UnlockHandle(section->glist.data);
|
|
|
|
VmAddr += section->glist.size;
|
|
FreeGList(§ion->glist);
|
|
} else {
|
|
VmAddr += pad + section->section.size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void WriteRelocs(void) {
|
|
MachOSegment *segment;
|
|
MachOSection *section;
|
|
MachOReloc *reloc;
|
|
enum reloc_type_ppc pairType;
|
|
UInt32 pairValue;
|
|
SInt32 scatterFlag;
|
|
UInt32 combo;
|
|
|
|
static char length_code[] = {
|
|
0, 0, 1, 1, 2
|
|
};
|
|
|
|
pairType = 0;
|
|
pairValue = 0;
|
|
scatterFlag = 0;
|
|
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
for (section = segment->firstSection; section; section = section->next) {
|
|
for (reloc = section->firstReloc; reloc; reloc = reloc->next) {
|
|
if (reloc->is_extern)
|
|
reloc->value += NumStabs;
|
|
|
|
switch (reloc->reltype) {
|
|
case PPC_RELOC_LO16:
|
|
case PPC_RELOC_HA16:
|
|
case PPC_RELOC_LO14:
|
|
pairType = reloc->reltype;
|
|
if (reloc->is_extern) {
|
|
pairValue = 0;
|
|
} else {
|
|
pairValue = reloc->next->address + GetSectVMAddr(reloc->value);
|
|
}
|
|
case PPC_RELOC_VANILLA:
|
|
case PPC_RELOC_BR14:
|
|
case PPC_RELOC_BR24:
|
|
case PPC_RELOC_HI16:
|
|
case PPC_RELOC_PB_LA_PTR:
|
|
AppendGListLong(&ObjFile, CTool_EndianConvertWord32(reloc->address));
|
|
AppendGListLong(&ObjFile,
|
|
CTool_EndianConvertWord32((reloc->value << 8) |
|
|
(reloc->is_pcrel << 7) |
|
|
(length_code[reloc->length] << 5) |
|
|
(reloc->is_extern << 4) |
|
|
reloc->reltype)
|
|
);
|
|
break;
|
|
case PPC_RELOC_PAIR:
|
|
switch (pairType) {
|
|
case PPC_RELOC_HI16:
|
|
case PPC_RELOC_HA16:
|
|
scatterFlag = 0;
|
|
reloc->address = pairValue & 0xFFFF;
|
|
break;
|
|
case PPC_RELOC_LO16:
|
|
scatterFlag = 0;
|
|
reloc->address = pairValue >> 16;
|
|
break;
|
|
case PPC_RELOC_HI16_SECTDIFF:
|
|
case PPC_RELOC_HA16_SECTDIFF:
|
|
scatterFlag = R_SCATTERED;
|
|
reloc->value += section->section.addr;
|
|
pairValue -= reloc->value;
|
|
reloc->address = pairValue & 0xFFFF;
|
|
break;
|
|
case PPC_RELOC_LO16_SECTDIFF:
|
|
scatterFlag = R_SCATTERED;
|
|
reloc->value += section->section.addr;
|
|
pairValue -= reloc->value;
|
|
reloc->address = pairValue >> 16;
|
|
break;
|
|
default:
|
|
CError_FATAL(891);
|
|
reloc->address = 0;
|
|
break;
|
|
}
|
|
|
|
pairValue = 0;
|
|
pairType = 0;
|
|
if (scatterFlag) {
|
|
AppendGListLong(&ObjFile,
|
|
CTool_EndianConvertWord32(scatterFlag |
|
|
(reloc->is_pcrel << 30) |
|
|
(length_code[reloc->length] << 28) |
|
|
(reloc->reltype << 24) |
|
|
reloc->address)
|
|
);
|
|
AppendGListLong(&ObjFile, CTool_EndianConvertWord32(reloc->value));
|
|
} else {
|
|
combo =
|
|
(reloc->value << 8) |
|
|
(reloc->is_pcrel << 7) |
|
|
(length_code[reloc->length] << 5) |
|
|
reloc->reltype;
|
|
AppendGListLong(&ObjFile, CTool_EndianConvertWord32(reloc->address));
|
|
AppendGListLong(&ObjFile, CTool_EndianConvertWord32(combo));
|
|
}
|
|
break;
|
|
case PPC_RELOC_SECTDIFF:
|
|
case PPC_RELOC_HI16_SECTDIFF:
|
|
case PPC_RELOC_LO16_SECTDIFF:
|
|
case PPC_RELOC_HA16_SECTDIFF:
|
|
// build scattered relocation
|
|
reloc->value = reloc->next->address + GetSectVMAddr(reloc->value);
|
|
pairType = reloc->reltype;
|
|
pairValue = reloc->value;
|
|
AppendGListLong(&ObjFile,
|
|
CTool_EndianConvertWord32(R_SCATTERED |
|
|
(reloc->is_pcrel << 30) |
|
|
(length_code[reloc->length] << 28) |
|
|
(reloc->reltype << 24) |
|
|
reloc->address)
|
|
);
|
|
AppendGListLong(&ObjFile, CTool_EndianConvertWord32(reloc->value));
|
|
break;
|
|
|
|
default:
|
|
CError_FATAL(930);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void WriteIndirectSymbolTable(void) {
|
|
UInt32 i;
|
|
UInt32 *ptr;
|
|
|
|
while (SymPad) {
|
|
AppendGListByte(&ObjFile, 0);
|
|
SymPad--;
|
|
}
|
|
|
|
COS_LockHandle(IndirectSymbolTable.data);
|
|
ptr = (UInt32 *) *IndirectSymbolTable.data;
|
|
for (i = 0; i < MachO_NumIndirectSym(); ptr++, i++) {
|
|
*ptr += NumStabs;
|
|
*ptr = CTool_EndianConvertWord32(*ptr);
|
|
}
|
|
|
|
AppendGListData(&ObjFile, *IndirectSymbolTable.data, IndirectSymbolTable.size);
|
|
COS_UnlockHandle(IndirectSymbolTable.data);
|
|
FreeGList(&IndirectSymbolTable);
|
|
}
|
|
|
|
static void WriteSymbolTable(void) {
|
|
MachOSymbol *symbol;
|
|
struct nlist nlist;
|
|
|
|
if (FirstStab) {
|
|
LastStab->next = FirstSym;
|
|
FirstSym = FirstStab;
|
|
}
|
|
|
|
for (symbol = FirstSym; symbol; symbol = symbol->next) {
|
|
nlist.n_strx = CTool_EndianConvertWord32(symbol->data.u.strx);
|
|
nlist.n_type = symbol->data.type;
|
|
if (symbol->data.section)
|
|
nlist.n_sect = symbol->data.section->num;
|
|
else
|
|
nlist.n_sect = 0;
|
|
nlist.n_desc = CTool_EndianConvertWord16(symbol->data.desc);
|
|
|
|
if (
|
|
symbol->data.type == N_STSYM ||
|
|
symbol->data.type == N_FUN ||
|
|
symbol->data.type == N_LCSYM ||
|
|
symbol->data.type == N_SLINE ||
|
|
symbol->data.type == N_SO ||
|
|
symbol->data.type == N_SOL ||
|
|
symbol->data.type == N_ENTRY ||
|
|
symbol->data.type == N_ECOML ||
|
|
(symbol->data.type & N_TYPE) == N_SECT
|
|
)
|
|
{
|
|
if (symbol->data.section)
|
|
symbol->data.value += symbol->data.section->section.addr;
|
|
else
|
|
CError_FATAL(1010);
|
|
}
|
|
|
|
nlist.n_value = CTool_EndianConvertWord32(symbol->data.value);
|
|
AppendGListData(&ObjFile, &nlist, sizeof(nlist));
|
|
}
|
|
}
|
|
|
|
static void WriteStringTable(void) {
|
|
COS_LockHandle(StringTable.data);
|
|
AppendGListData(&ObjFile, *StringTable.data, StringTable.size);
|
|
COS_UnlockHandle(StringTable.data);
|
|
}
|
|
|
|
void MachO_Finish(void) {
|
|
struct mach_header hdr;
|
|
|
|
CodeSize = 0;
|
|
IdataSize = UdataSize = 0;
|
|
VmAddr = 0;
|
|
FileOffset = sizeof(hdr);
|
|
|
|
hdr.ncmds = AllocateForLoadCommands();
|
|
|
|
FileOffset += 24; // what am I?
|
|
hdr.ncmds++;
|
|
|
|
if (copts.codegen_dynamic) {
|
|
FileOffset += 80; // what am I?
|
|
hdr.ncmds++;
|
|
}
|
|
|
|
hdr.ncmds = CTool_EndianConvertWord32(hdr.ncmds);
|
|
hdr.sizeofcmds = CTool_EndianConvertWord32(FileOffset - sizeof(hdr));
|
|
|
|
AllocateAddresses();
|
|
ApplyRelocs();
|
|
AllocForRelocs();
|
|
|
|
SymPad = (4 - (FileOffset & 3)) & 3;
|
|
FileOffset += SymPad;
|
|
IndirectSymbolTableOffset = 0;
|
|
|
|
if (IndirectSymbolTable.size > 0) {
|
|
IndirectSymbolTableOffset = FileOffset;
|
|
FileOffset += IndirectSymbolTable.size;
|
|
}
|
|
|
|
InitGList(&ObjFile, 4096);
|
|
|
|
hdr.magic = CTool_EndianConvertWord32(MH_MAGIC);
|
|
hdr.cputype = CTool_EndianConvertWord32(CPU_TYPE_POWERPC);
|
|
hdr.cpusubtype = CTool_EndianConvertWord32(CPU_SUBTYPE_MC98000_ALL);
|
|
hdr.filetype = CTool_EndianConvertWord32(MH_OBJECT);
|
|
hdr.flags = 0;
|
|
AppendGListData(&ObjFile, &hdr, sizeof(hdr));
|
|
|
|
WriteSegLoadCommands();
|
|
WriteSymtabLoadCommand();
|
|
if (copts.codegen_dynamic)
|
|
WriteDynamicSymtabLoadCommand();
|
|
WriteSectionData();
|
|
WriteRelocs();
|
|
WriteIndirectSymbolTable();
|
|
WriteSymbolTable();
|
|
WriteStringTable();
|
|
|
|
COS_ResizeHandle(ObjFile.data, ObjFile.size);
|
|
|
|
cparamblkptr->objectDataHandle = ObjFile.data;
|
|
cparamblkptr->objectdata.codesize = CodeSize;
|
|
cparamblkptr->objectdata.udatasize = UdataSize;
|
|
cparamblkptr->objectdata.idatasize = IdataSize;
|
|
}
|
|
|
|
void MachO_Cleanup(void) {
|
|
if (StringTable.data)
|
|
FreeGList(&StringTable);
|
|
if (IndirectSymbolTable.data)
|
|
FreeGList(&IndirectSymbolTable);
|
|
}
|
|
|
|
MachOSegment *MachO_CreateSegment(char *segname, int maxprot, int initprot, UInt32 flags) {
|
|
MachOSegment *segment = galloc(sizeof(MachOSegment));
|
|
|
|
memset(&segment->cmd, 0, sizeof(segment->cmd));
|
|
segment->cmd.cmd = LC_SEGMENT;
|
|
strncpy(segment->cmd.segname, segname, sizeof(segment->cmd.segname));
|
|
segment->cmd.maxprot = maxprot;
|
|
segment->cmd.initprot = initprot;
|
|
segment->cmd.flags = flags;
|
|
|
|
segment->firstSection = segment->lastSection = NULL;
|
|
segment->next = NULL;
|
|
if (FirstSeg == NULL)
|
|
FirstSeg = segment;
|
|
else
|
|
LastSeg->next = segment;
|
|
LastSeg = segment;
|
|
|
|
return segment;
|
|
}
|
|
|
|
MachOSection *MachO_CreateSection(MachOSegment *segment, char *segname, char *sectname, UInt32 align, UInt32 flags, UInt32 sectionID) {
|
|
MachOSection *section;
|
|
UInt32 alignConv;
|
|
|
|
alignConv = 0;
|
|
while (!(align & 1)) {
|
|
align >>= 1;
|
|
alignConv++;
|
|
}
|
|
|
|
section = galloc(sizeof(MachOSection));
|
|
memset(section, 0, sizeof(MachOSection));
|
|
|
|
strncpy(section->section.segname, segname, sizeof(section->section.segname));
|
|
strncpy(section->section.sectname, sectname, sizeof(section->section.sectname));
|
|
section->section.align = alignConv;
|
|
section->section.flags = flags;
|
|
|
|
section->num = ++SectNum;
|
|
section->id = sectionID;
|
|
|
|
section->next = NULL;
|
|
if (segment->firstSection == NULL)
|
|
segment->firstSection = section;
|
|
else
|
|
segment->lastSection->next = section;
|
|
segment->lastSection = section;
|
|
|
|
segment->cmd.nsects++;
|
|
|
|
return section;
|
|
}
|
|
|
|
GList *MachO_GetGList(MachOSection *section) {
|
|
if (!section->glist.data)
|
|
InitGList(§ion->glist, 256);
|
|
return §ion->glist;
|
|
}
|
|
|
|
void MachO_SetSectionSize(void) {
|
|
// empty, unused, unknown args
|
|
}
|
|
|
|
void MachO_Relocate(MachOSection *section, UInt32 address, UInt32 value, char length, char is_pcrel, Boolean is_extern, int reltype) {
|
|
MachOReloc *reloc;
|
|
|
|
reloc = galloc(sizeof(MachOReloc));
|
|
reloc->address = address;
|
|
reloc->value = value;
|
|
reloc->length = length;
|
|
reloc->is_pcrel = is_pcrel;
|
|
reloc->is_extern = is_extern;
|
|
reloc->reltype = reltype;
|
|
|
|
reloc->next = NULL;
|
|
if (section->firstReloc == NULL)
|
|
section->firstReloc = reloc;
|
|
else
|
|
section->lastReloc->next = reloc;
|
|
section->lastReloc = reloc;
|
|
|
|
section->section.nreloc++;
|
|
}
|
|
|
|
static SInt32 DeclareString(char *str) {
|
|
SInt32 offset;
|
|
|
|
if (str) {
|
|
offset = StringTable.size;
|
|
AppendGListID(&StringTable, str);
|
|
} else {
|
|
offset = 0;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
UInt32 MachO_DeclareSymbol(char *name, MachOSection *section, UInt32 value, Boolean isAbsolute, short type, short desc) {
|
|
MachOSymbol *symbol;
|
|
|
|
symbol = galloc(sizeof(MachOSymbol));
|
|
memset(symbol, 0, sizeof(MachOSymbol));
|
|
|
|
if (section) {
|
|
if (type) {
|
|
if (nextdefsym == 0)
|
|
iextdefsym = SymNum;
|
|
nextdefsym++;
|
|
} else {
|
|
if (nlocalsym == 0)
|
|
ilocalsym = SymNum;
|
|
nlocalsym++;
|
|
}
|
|
symbol->data.type = type | N_SECT;
|
|
symbol->data.section = section;
|
|
} else if (isAbsolute) {
|
|
symbol->data.type = type | N_ABS;
|
|
} else {
|
|
if (nundefsym == 0)
|
|
iundefsym = SymNum;
|
|
nundefsym++;
|
|
symbol->data.type = type & ~N_PEXT;
|
|
}
|
|
|
|
symbol->data.value = value;
|
|
symbol->data.u.strx = DeclareString(name);
|
|
symbol->data.desc = desc;
|
|
symbol->index = SymNum++;
|
|
|
|
if (FirstSym == NULL)
|
|
FirstSym = symbol;
|
|
else
|
|
LastSym->next = symbol;
|
|
LastSym = symbol;
|
|
|
|
return symbol->index;
|
|
}
|
|
|
|
void MachO_ReOrderSections(void) {
|
|
MachOSection *section;
|
|
MachOSegment *segment;
|
|
MachOSection *prev;
|
|
MachOSection *firstRemoved;
|
|
MachOSection *lastRemoved;
|
|
UInt32 counter;
|
|
|
|
counter = 0;
|
|
for (segment = FirstSeg; segment; segment = segment->next) {
|
|
prev = NULL;
|
|
section = segment->firstSection;
|
|
firstRemoved = lastRemoved = NULL;
|
|
while (section) {
|
|
if (section->section.size && section->glist.data == NULL && section != segment->firstSection) {
|
|
// detach this section
|
|
if (prev)
|
|
prev->next = section->next;
|
|
else
|
|
segment->firstSection = section->next;
|
|
|
|
if (section == segment->lastSection)
|
|
segment->lastSection = prev;
|
|
|
|
section->next = NULL;
|
|
|
|
// add it to the list to be pushed to the end
|
|
if (firstRemoved == NULL)
|
|
firstRemoved = section;
|
|
else
|
|
lastRemoved->next = section;
|
|
lastRemoved = section;
|
|
|
|
// continue iterating
|
|
if (prev)
|
|
section = prev->next;
|
|
else
|
|
section = segment->firstSection;
|
|
} else {
|
|
prev = section;
|
|
section = section->next;
|
|
}
|
|
}
|
|
|
|
// attach the other sections
|
|
if (firstRemoved) {
|
|
if (segment->firstSection == NULL)
|
|
segment->firstSection = firstRemoved;
|
|
else
|
|
segment->lastSection->next = firstRemoved;
|
|
segment->lastSection = lastRemoved;
|
|
}
|
|
|
|
// renumber them all
|
|
for (section = segment->firstSection; section; section = section->next)
|
|
section->num = ++counter;
|
|
}
|
|
}
|
|
|
|
void MachO_AddIndirectSymbol(SInt32 symbol) {
|
|
CError_ASSERT(1577, symbol >= 0);
|
|
|
|
AppendGListLong(&IndirectSymbolTable, symbol);
|
|
}
|
|
|
|
UInt32 MachO_NumIndirectSym(void) {
|
|
return IndirectSymbolTable.size / 4;
|
|
}
|
|
|
|
SInt32 MachO_OutputStab(SymbolData *data, SInt32 strIndex) {
|
|
MachOSymbol *symbol;
|
|
|
|
symbol = galloc(sizeof(MachOSymbol));
|
|
memset(symbol, 0, sizeof(MachOSymbol));
|
|
if (strIndex == -1)
|
|
data->u.strx = DeclareString(data->u.name);
|
|
else
|
|
data->u.strx = strIndex;
|
|
|
|
memcpy(&symbol->data, data, sizeof(SymbolData));
|
|
|
|
if (FirstStab == NULL)
|
|
FirstStab = symbol;
|
|
else
|
|
LastStab->next = symbol;
|
|
LastStab = symbol;
|
|
NumStabs++;
|
|
|
|
return data->u.strx;
|
|
}
|