]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===-- PPCAsmBackend.cpp - PPC Assembler Backend -------------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | ||
10 | #include "MCTargetDesc/PPCMCTargetDesc.h" | |
11 | #include "MCTargetDesc/PPCFixupKinds.h" | |
12 | #include "llvm/MC/MCAsmBackend.h" | |
85aaf69f | 13 | #include "llvm/MC/MCAssembler.h" |
1a4d82fc | 14 | #include "llvm/MC/MCELF.h" |
223e47cc LB |
15 | #include "llvm/MC/MCELFObjectWriter.h" |
16 | #include "llvm/MC/MCFixupKindInfo.h" | |
17 | #include "llvm/MC/MCMachObjectWriter.h" | |
223e47cc | 18 | #include "llvm/MC/MCObjectWriter.h" |
970d7e83 | 19 | #include "llvm/MC/MCSectionMachO.h" |
223e47cc | 20 | #include "llvm/MC/MCValue.h" |
223e47cc LB |
21 | #include "llvm/Support/ELF.h" |
22 | #include "llvm/Support/ErrorHandling.h" | |
1a4d82fc | 23 | #include "llvm/Support/MachO.h" |
223e47cc LB |
24 | #include "llvm/Support/TargetRegistry.h" |
25 | using namespace llvm; | |
26 | ||
1a4d82fc | 27 | static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { |
223e47cc LB |
28 | switch (Kind) { |
29 | default: | |
30 | llvm_unreachable("Unknown fixup kind!"); | |
31 | case FK_Data_1: | |
32 | case FK_Data_2: | |
33 | case FK_Data_4: | |
970d7e83 | 34 | case FK_Data_8: |
970d7e83 | 35 | case PPC::fixup_ppc_nofixup: |
223e47cc LB |
36 | return Value; |
37 | case PPC::fixup_ppc_brcond14: | |
1a4d82fc | 38 | case PPC::fixup_ppc_brcond14abs: |
970d7e83 | 39 | return Value & 0xfffc; |
223e47cc | 40 | case PPC::fixup_ppc_br24: |
1a4d82fc | 41 | case PPC::fixup_ppc_br24abs: |
223e47cc | 42 | return Value & 0x3fffffc; |
1a4d82fc | 43 | case PPC::fixup_ppc_half16: |
223e47cc | 44 | return Value & 0xffff; |
1a4d82fc JJ |
45 | case PPC::fixup_ppc_half16ds: |
46 | return Value & 0xfffc; | |
223e47cc LB |
47 | } |
48 | } | |
49 | ||
1a4d82fc JJ |
50 | static unsigned getFixupKindNumBytes(unsigned Kind) { |
51 | switch (Kind) { | |
52 | default: | |
53 | llvm_unreachable("Unknown fixup kind!"); | |
54 | case FK_Data_1: | |
55 | return 1; | |
56 | case FK_Data_2: | |
57 | case PPC::fixup_ppc_half16: | |
58 | case PPC::fixup_ppc_half16ds: | |
59 | return 2; | |
60 | case FK_Data_4: | |
61 | case PPC::fixup_ppc_brcond14: | |
62 | case PPC::fixup_ppc_brcond14abs: | |
63 | case PPC::fixup_ppc_br24: | |
64 | case PPC::fixup_ppc_br24abs: | |
65 | return 4; | |
66 | case FK_Data_8: | |
67 | return 8; | |
68 | case PPC::fixup_ppc_nofixup: | |
69 | return 0; | |
970d7e83 | 70 | } |
1a4d82fc JJ |
71 | } |
72 | ||
73 | namespace { | |
223e47cc LB |
74 | |
75 | class PPCAsmBackend : public MCAsmBackend { | |
1a4d82fc JJ |
76 | const Target &TheTarget; |
77 | bool IsLittleEndian; | |
223e47cc | 78 | public: |
1a4d82fc JJ |
79 | PPCAsmBackend(const Target &T, bool isLittle) : MCAsmBackend(), TheTarget(T), |
80 | IsLittleEndian(isLittle) {} | |
223e47cc | 81 | |
1a4d82fc JJ |
82 | unsigned getNumFixupKinds() const override { |
83 | return PPC::NumTargetFixupKinds; | |
84 | } | |
223e47cc | 85 | |
1a4d82fc JJ |
86 | const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { |
87 | const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = { | |
223e47cc LB |
88 | // name offset bits flags |
89 | { "fixup_ppc_br24", 6, 24, MCFixupKindInfo::FKF_IsPCRel }, | |
90 | { "fixup_ppc_brcond14", 16, 14, MCFixupKindInfo::FKF_IsPCRel }, | |
1a4d82fc JJ |
91 | { "fixup_ppc_br24abs", 6, 24, 0 }, |
92 | { "fixup_ppc_brcond14abs", 16, 14, 0 }, | |
93 | { "fixup_ppc_half16", 0, 16, 0 }, | |
94 | { "fixup_ppc_half16ds", 0, 14, 0 }, | |
970d7e83 | 95 | { "fixup_ppc_nofixup", 0, 0, 0 } |
223e47cc | 96 | }; |
1a4d82fc JJ |
97 | const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = { |
98 | // name offset bits flags | |
99 | { "fixup_ppc_br24", 2, 24, MCFixupKindInfo::FKF_IsPCRel }, | |
100 | { "fixup_ppc_brcond14", 2, 14, MCFixupKindInfo::FKF_IsPCRel }, | |
101 | { "fixup_ppc_br24abs", 2, 24, 0 }, | |
102 | { "fixup_ppc_brcond14abs", 2, 14, 0 }, | |
103 | { "fixup_ppc_half16", 0, 16, 0 }, | |
104 | { "fixup_ppc_half16ds", 2, 14, 0 }, | |
105 | { "fixup_ppc_nofixup", 0, 0, 0 } | |
106 | }; | |
223e47cc LB |
107 | |
108 | if (Kind < FirstTargetFixupKind) | |
109 | return MCAsmBackend::getFixupKindInfo(Kind); | |
110 | ||
111 | assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && | |
112 | "Invalid kind!"); | |
1a4d82fc | 113 | return (IsLittleEndian? InfosLE : InfosBE)[Kind - FirstTargetFixupKind]; |
223e47cc LB |
114 | } |
115 | ||
970d7e83 | 116 | void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, |
1a4d82fc | 117 | uint64_t Value, bool IsPCRel) const override { |
970d7e83 LB |
118 | Value = adjustFixupValue(Fixup.getKind(), Value); |
119 | if (!Value) return; // Doesn't change encoding. | |
120 | ||
121 | unsigned Offset = Fixup.getOffset(); | |
1a4d82fc | 122 | unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); |
970d7e83 LB |
123 | |
124 | // For each byte of the fragment that the fixup touches, mask in the bits | |
125 | // from the fixup value. The Value has been "split up" into the appropriate | |
126 | // bitfields above. | |
1a4d82fc JJ |
127 | for (unsigned i = 0; i != NumBytes; ++i) { |
128 | unsigned Idx = IsLittleEndian ? i : (NumBytes - 1 - i); | |
129 | Data[Offset + i] |= uint8_t((Value >> (Idx * 8)) & 0xff); | |
130 | } | |
970d7e83 LB |
131 | } |
132 | ||
1a4d82fc JJ |
133 | void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, |
134 | const MCFixup &Fixup, const MCFragment *DF, | |
135 | const MCValue &Target, uint64_t &Value, | |
136 | bool &IsResolved) override { | |
137 | switch ((PPC::Fixups)Fixup.getKind()) { | |
138 | default: break; | |
139 | case PPC::fixup_ppc_br24: | |
140 | case PPC::fixup_ppc_br24abs: | |
141 | // If the target symbol has a local entry point we must not attempt | |
142 | // to resolve the fixup directly. Emit a relocation and leave | |
143 | // resolution of the final target address to the linker. | |
144 | if (const MCSymbolRefExpr *A = Target.getSymA()) { | |
145 | const MCSymbolData &Data = Asm.getSymbolData(A->getSymbol()); | |
146 | // The "other" values are stored in the last 6 bits of the second byte. | |
147 | // The traditional defines for STO values assume the full byte and thus | |
148 | // the shift to pack it. | |
149 | unsigned Other = MCELF::getOther(Data) << 2; | |
150 | if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0) | |
151 | IsResolved = false; | |
152 | } | |
153 | break; | |
154 | } | |
155 | } | |
156 | ||
157 | bool mayNeedRelaxation(const MCInst &Inst) const override { | |
223e47cc LB |
158 | // FIXME. |
159 | return false; | |
160 | } | |
161 | ||
162 | bool fixupNeedsRelaxation(const MCFixup &Fixup, | |
163 | uint64_t Value, | |
970d7e83 | 164 | const MCRelaxableFragment *DF, |
1a4d82fc | 165 | const MCAsmLayout &Layout) const override { |
223e47cc LB |
166 | // FIXME. |
167 | llvm_unreachable("relaxInstruction() unimplemented"); | |
168 | } | |
169 | ||
170 | ||
1a4d82fc | 171 | void relaxInstruction(const MCInst &Inst, MCInst &Res) const override { |
223e47cc LB |
172 | // FIXME. |
173 | llvm_unreachable("relaxInstruction() unimplemented"); | |
174 | } | |
175 | ||
1a4d82fc JJ |
176 | bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override { |
177 | uint64_t NumNops = Count / 4; | |
178 | for (uint64_t i = 0; i != NumNops; ++i) | |
179 | OW->Write32(0x60000000); | |
180 | ||
181 | switch (Count % 4) { | |
182 | default: break; // No leftover bytes to write | |
183 | case 1: OW->Write8(0); break; | |
184 | case 2: OW->Write16(0); break; | |
185 | case 3: OW->Write16(0); OW->Write8(0); break; | |
186 | } | |
187 | ||
223e47cc LB |
188 | return true; |
189 | } | |
190 | ||
191 | unsigned getPointerSize() const { | |
192 | StringRef Name = TheTarget.getName(); | |
1a4d82fc | 193 | if (Name == "ppc64" || Name == "ppc64le") return 8; |
223e47cc LB |
194 | assert(Name == "ppc32" && "Unknown target name!"); |
195 | return 4; | |
196 | } | |
1a4d82fc JJ |
197 | |
198 | bool isLittleEndian() const { | |
199 | return IsLittleEndian; | |
200 | } | |
223e47cc LB |
201 | }; |
202 | } // end anonymous namespace | |
203 | ||
204 | ||
205 | // FIXME: This should be in a separate file. | |
206 | namespace { | |
207 | class DarwinPPCAsmBackend : public PPCAsmBackend { | |
208 | public: | |
1a4d82fc | 209 | DarwinPPCAsmBackend(const Target &T) : PPCAsmBackend(T, false) { } |
223e47cc | 210 | |
1a4d82fc | 211 | MCObjectWriter *createObjectWriter(raw_ostream &OS) const override { |
223e47cc | 212 | bool is64 = getPointerSize() == 8; |
1a4d82fc JJ |
213 | return createPPCMachObjectWriter( |
214 | OS, | |
215 | /*Is64Bit=*/is64, | |
216 | (is64 ? MachO::CPU_TYPE_POWERPC64 : MachO::CPU_TYPE_POWERPC), | |
217 | MachO::CPU_SUBTYPE_POWERPC_ALL); | |
223e47cc LB |
218 | } |
219 | }; | |
220 | ||
221 | class ELFPPCAsmBackend : public PPCAsmBackend { | |
222 | uint8_t OSABI; | |
223 | public: | |
1a4d82fc JJ |
224 | ELFPPCAsmBackend(const Target &T, bool IsLittleEndian, uint8_t OSABI) : |
225 | PPCAsmBackend(T, IsLittleEndian), OSABI(OSABI) { } | |
223e47cc | 226 | |
223e47cc | 227 | |
1a4d82fc | 228 | MCObjectWriter *createObjectWriter(raw_ostream &OS) const override { |
223e47cc | 229 | bool is64 = getPointerSize() == 8; |
1a4d82fc | 230 | return createPPCELFObjectWriter(OS, is64, isLittleEndian(), OSABI); |
223e47cc LB |
231 | } |
232 | }; | |
233 | ||
234 | } // end anonymous namespace | |
235 | ||
1a4d82fc JJ |
236 | MCAsmBackend *llvm::createPPCAsmBackend(const Target &T, |
237 | const MCRegisterInfo &MRI, | |
238 | StringRef TT, StringRef CPU) { | |
223e47cc LB |
239 | if (Triple(TT).isOSDarwin()) |
240 | return new DarwinPPCAsmBackend(T); | |
241 | ||
242 | uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(Triple(TT).getOS()); | |
1a4d82fc JJ |
243 | bool IsLittleEndian = Triple(TT).getArch() == Triple::ppc64le; |
244 | return new ELFPPCAsmBackend(T, IsLittleEndian, OSABI); | |
223e47cc | 245 | } |