First pass at supporting relocations. Relocations are written correctly to
[oota-llvm.git] / lib / Target / PowerPC / PPCMachOWriter.cpp
1 //===-- PPCMachOWriter.cpp - Emit a Mach-O file for the PowerPC backend ---===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Nate Begeman and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements a Mach-O writer for the PowerPC backend.  The public
11 // interface to this file is the createPPCMachOObjectWriterPass function.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "PPCRelocations.h"
16 #include "PPCTargetMachine.h"
17 #include "llvm/PassManager.h"
18 #include "llvm/CodeGen/MachOWriter.h"
19 #include "llvm/Support/Compiler.h"
20 using namespace llvm;
21
22 namespace {
23   class VISIBILITY_HIDDEN PPCMachOWriter : public MachOWriter {
24   public:
25     PPCMachOWriter(std::ostream &O, PPCTargetMachine &TM) : MachOWriter(O, TM) {
26       if (TM.getTargetData()->getPointerSizeInBits() == 64) {
27         Header.cputype = MachOHeader::CPU_TYPE_POWERPC64;
28       } else {
29         Header.cputype = MachOHeader::CPU_TYPE_POWERPC;
30       }
31       Header.cpusubtype = MachOHeader::CPU_SUBTYPE_POWERPC_ALL;
32     }
33
34     virtual void GetTargetRelocation(MachOSection &MOS, MachineRelocation &MR,
35                                      uint64_t Addr);
36     
37     // Constants for the relocation r_type field.
38     // see <mach-o/ppc/reloc.h>
39     enum { PPC_RELOC_VANILLA, // generic relocation
40            PPC_RELOC_PAIR,    // the second relocation entry of a pair
41            PPC_RELOC_BR14,    // 14 bit branch displacement to word address
42            PPC_RELOC_BR24,    // 24 bit branch displacement to word address
43            PPC_RELOC_HI16,    // a PAIR follows with the low 16 bits
44            PPC_RELOC_LO16,    // a PAIR follows with the high 16 bits
45            PPC_RELOC_HA16,    // a PAIR follows, which is sign extended to 32b
46            PPC_RELOC_LO14     // LO16 with low 2 bits implicitly zero
47     };
48   };
49 }
50
51 /// addPPCMachOObjectWriterPass - Returns a pass that outputs the generated code
52 /// as a Mach-O object file.
53 ///
54 void llvm::addPPCMachOObjectWriterPass(FunctionPassManager &FPM,
55                                        std::ostream &O, PPCTargetMachine &TM) {
56   PPCMachOWriter *EW = new PPCMachOWriter(O, TM);
57   FPM.add(EW);
58   FPM.add(createPPCCodeEmitterPass(TM, EW->getMachineCodeEmitter()));
59 }
60
61 /// GetTargetRelocation - For the MachineRelocation MR, convert it to one or
62 /// more PowerPC MachORelocation(s), add the new relocations to the
63 /// MachOSection, and rewrite the instruction at the section offset if required 
64 /// by that relocation type.
65 void PPCMachOWriter::GetTargetRelocation(MachOSection &MOS,
66                                          MachineRelocation &MR,
67                                          uint64_t Addr) {
68   // Keep track of whether or not this is an externally defined relocation.
69   uint32_t index = MOS.Index;
70   bool     isExtern = false;
71   
72   // Get the address of the instruction to rewrite
73   unsigned char *RelocPos = &MOS.SectionData[0] + MR.getMachineCodeOffset();
74   
75   // Get the address of whatever it is we're relocating, if possible.
76   if (MR.isGlobalValue()) {
77     // determine whether or not its external and then figure out what section
78     // we put it in if it's a locally defined symbol.
79   } else if (MR.isString()) {
80     // lookup in global values?
81   } else {
82     assert((MR.isConstantPoolIndex() || MR.isJumpTableIndex()) &&
83            "Unhandled MachineRelocation type!");
84   }
85   
86   switch ((PPC::RelocationType)MR.getRelocationType()) {
87   default: assert(0 && "Unknown PPC relocation type!");
88   case PPC::reloc_pcrel_bx:
89   case PPC::reloc_pcrel_bcx:
90   case PPC::reloc_absolute_low_ix:
91     assert(0 && "Unhandled PPC relocation type!");
92     break;
93   case PPC::reloc_absolute_high:
94     {
95       MachORelocation HA16(MR.getMachineCodeOffset(), index, false, 2, isExtern, 
96                            PPC_RELOC_HA16);
97       MachORelocation PAIR(Addr & 0xFFFF, 0xFFFFFF, false, 2, isExtern,
98                            PPC_RELOC_PAIR);
99       outword(RelocBuffer, HA16.r_address);
100       outword(RelocBuffer, HA16.getPackedFields());
101       outword(RelocBuffer, PAIR.r_address);
102       outword(RelocBuffer, PAIR.getPackedFields());
103     }
104     MOS.nreloc += 2;
105     Addr += 0x8000;
106     *(unsigned *)RelocPos &= 0xFFFF0000;
107     *(unsigned *)RelocPos |= ((Addr >> 16) & 0xFFFF);
108     break;
109   case PPC::reloc_absolute_low:
110     {
111       MachORelocation LO16(MR.getMachineCodeOffset(), index, false, 2, isExtern, 
112                            PPC_RELOC_LO16);
113       MachORelocation PAIR(Addr >> 16, 0xFFFFFF, false, 2, isExtern,
114                            PPC_RELOC_PAIR);
115       outword(RelocBuffer, LO16.r_address);
116       outword(RelocBuffer, LO16.getPackedFields());
117       outword(RelocBuffer, PAIR.r_address);
118       outword(RelocBuffer, PAIR.getPackedFields());
119     }
120     MOS.nreloc += 2;
121     *(unsigned *)RelocPos &= 0xFFFF0000;
122     *(unsigned *)RelocPos |= (Addr & 0xFFFF);
123     break;
124   }
125 }