1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.tools.jaotc.binformat.elf; 25 26 import java.io.IOException; 27 import java.nio.charset.StandardCharsets; 28 import java.util.ArrayList; 29 import java.util.Collection; 30 import java.util.List; 31 import java.util.Map; 32 33 import jdk.tools.jaotc.binformat.BinaryContainer; 34 import jdk.tools.jaotc.binformat.ByteContainer; 35 import jdk.tools.jaotc.binformat.CodeContainer; 36 import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; 37 import jdk.tools.jaotc.binformat.Relocation; 38 import jdk.tools.jaotc.binformat.Relocation.RelocType; 39 import jdk.tools.jaotc.binformat.Symbol; 40 import jdk.tools.jaotc.binformat.Symbol.Binding; 41 import jdk.tools.jaotc.binformat.Symbol.Kind; 42 import jdk.tools.jaotc.jnilibelf.ELFContainer; 43 import jdk.tools.jaotc.jnilibelf.ELFSymbol; 44 import jdk.tools.jaotc.jnilibelf.JNIELFContainer; 45 import jdk.tools.jaotc.jnilibelf.JNIELFRelocation; 46 import jdk.tools.jaotc.jnilibelf.JNIELFTargetInfo; 47 import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.ELF; 48 import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Cmd; 49 import jdk.tools.jaotc.jnilibelf.JNILibELFAPI.LibELF.Elf_Type; 50 import jdk.tools.jaotc.jnilibelf.Pointer; 51 52 public class JELFRelocObject { 53 54 private final BinaryContainer binContainer; 55 56 private final JNIELFContainer elfContainer; 57 58 private final int segmentSize; 59 60 public JELFRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) { 61 this.binContainer = binContainer; 62 this.elfContainer = new JNIELFContainer(outputFileName, aotVersion); 63 this.segmentSize = binContainer.getCodeSegmentSize(); 64 } 65 66 private void createByteSection(ByteContainer c, int scnFlags) { 67 byte[] scnData = c.getByteArray(); 68 int scnType = ELF.SHT_PROGBITS; 69 boolean zeros = !c.hasRelocations(); 70 if (zeros) { 71 for (byte b : scnData) { 72 if (b != 0) { 73 zeros = false; 74 break; 75 } 76 } 77 if (zeros) { 78 scnType = ELF.SHT_NOBITS; 79 } 80 } 81 82 int sectionId = elfContainer.createSection(c.getContainerName(), scnData, Elf_Type.ELF_T_BYTE, segmentSize, scnType, scnFlags, ELF.SHN_UNDEF, 0); 83 c.setSectionId(sectionId); 84 // Clear out code section data to allow for GC 85 c.clear(); 86 } 87 88 private void createCodeSection(CodeContainer c) { 89 createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_EXECINSTR); 90 } 91 92 private void createReadOnlySection(ReadOnlyDataContainer c) { 93 createByteSection(c, ELF.SHF_ALLOC); 94 } 95 96 private void createReadWriteSection(ByteContainer c) { 97 createByteSection(c, ELF.SHF_ALLOC | ELF.SHF_WRITE); 98 } 99 100 /** 101 * Create an ELF relocatable object using jdk.tools.jaotc.jnilibelf API. 102 * 103 * @param relocationTable 104 * @param symbols 105 * @throws IOException throws {@code IOException} as a result of file system access failures. 106 */ 107 public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException { 108 // Allocate ELF Header 109 elfContainer.createELFHeader(ELF.ET_REL); 110 111 // Create text section 112 createCodeSection(binContainer.getCodeContainer()); 113 createReadOnlySection(binContainer.getMetaspaceNamesContainer()); 114 createReadOnlySection(binContainer.getKlassesOffsetsContainer()); 115 createReadOnlySection(binContainer.getMethodsOffsetsContainer()); 116 createReadOnlySection(binContainer.getKlassesDependenciesContainer()); 117 createReadWriteSection(binContainer.getMetaspaceGotContainer()); 118 createReadWriteSection(binContainer.getMetadataGotContainer()); 119 createReadWriteSection(binContainer.getMethodStateContainer()); 120 createReadWriteSection(binContainer.getOopGotContainer()); 121 createReadWriteSection(binContainer.getMethodMetadataContainer()); 122 createReadOnlySection(binContainer.getStubsOffsetsContainer()); 123 createReadOnlySection(binContainer.getHeaderContainer().getContainer()); 124 createReadOnlySection(binContainer.getCodeSegmentsContainer()); 125 createReadOnlySection(binContainer.getConstantDataContainer()); 126 createReadOnlySection(binContainer.getConfigContainer()); 127 128 // createExternalLinkage(); 129 130 createCodeSection(binContainer.getExtLinkageContainer()); 131 createReadWriteSection(binContainer.getExtLinkageGOTContainer()); 132 133 // Get ELF symbol data from BinaryContainer object's symbol tables 134 createELFSymbolTables(symbols); 135 136 // Create string table section and symbol table sections in 137 // that order since symtab section needs to set the index of strtab in sh_link field 138 int strTabSectionIndex = elfContainer.createSection(".strtab", elfContainer.getStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0); 139 140 // Now create .symtab section with the symtab data constructed. On Linux, sh_link of symtab 141 // contains the index of string table its symbols reference and 142 // sh_info contains the index of first non-local symbol 143 int scnInfo = elfContainer.getFirstNonLocalSymbolIndex(); 144 int symTabSectionIndex = elfContainer.createSection(".symtab", getELFSymbolTableData(), Elf_Type.ELF_T_SYM, 8, ELF.SHT_SYMTAB, ELF.SHF_ALLOC, strTabSectionIndex, scnInfo); 145 146 buildRelocations(relocationTable, symTabSectionIndex); 147 148 // Now, finally, after creating all sections, create shstrtab section 149 elfContainer.createSection(".shstrtab", elfContainer.getShStrTabContent().getBytes(StandardCharsets.UTF_8), Elf_Type.ELF_T_BYTE, 1, ELF.SHT_STRTAB, 0, ELF.SHN_UNDEF, 0); 150 151 // Run elf_update 152 elfContainer.elfUpdate(Elf_Cmd.ELF_C_NULL); 153 154 // Run elfUpdate again to write it out. 155 elfContainer.elfUpdate(Elf_Cmd.ELF_C_WRITE); 156 // Finish ELF processing 157 elfContainer.elfEnd(); 158 } 159 160 private void buildRelocations(Map<Symbol, List<Relocation>> relocationTable, final int symTabSectionIndex) { 161 /* 162 * Create relocation sections. This needs to be done after symbol table sections were 163 * created since relocation entries will need indices of sections to which they apply. 164 */ 165 createELFRelocationTables(relocationTable); 166 createAllRelocationSections(new SymTabELFContainer(symTabSectionIndex)); 167 } 168 169 /** 170 * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF 171 * symbol table and ELF symbol table are created from BinaryContainer's symbol info. 172 * 173 * @param symbols 174 */ 175 private void createELFSymbolTables(Collection<Symbol> symbols) { 176 // First, create the initial null symbol. This is a local symbol. 177 elfContainer.createELFSymbolEntry("", 0, 0, ELF.SHN_UNDEF, 0, 0, true); 178 179 // Now create ELF symbol entries for all symbols. 180 for (Symbol symbol : symbols) { 181 // Get the index of section this symbol is defined in. 182 int secHdrIndex = symbol.getSection().getSectionId(); 183 boolean isLocal = (symbol.getBinding() == Binding.LOCAL); 184 ELFSymbol elfSymbol = elfContainer.createELFSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), secHdrIndex, symbol.getSize(), symbol.getOffset(), isLocal); 185 symbol.setElfSymbol(elfSymbol); 186 } 187 } 188 189 /** 190 * Construct ELF symbol data from BinaryContainer object's symbol tables. 191 * 192 * @return a byte array containing the symbol table 193 */ 194 private byte[] getELFSymbolTableData() { 195 final int entrySize = JNIELFTargetInfo.sizeOfSymtabEntry(); 196 197 // First, add all local symbols. 198 List<ELFSymbol> localSymbols = elfContainer.getLocalSymbols(); 199 List<ELFSymbol> globalSymbols = elfContainer.getGlobalSymbols(); 200 201 int localSymCount = localSymbols.size(); 202 int globalSymCount = globalSymbols.size(); 203 byte[] sectionDataArray = new byte[(localSymCount + globalSymCount) * entrySize]; 204 205 for (int i = 0; i < localSymCount; i++) { 206 ELFSymbol symbol = localSymbols.get(i); 207 Pointer address = symbol.getAddress(); 208 address.copyBytesTo(sectionDataArray, entrySize, i * entrySize); 209 } 210 211 // Next, add all global symbols. 212 213 for (int i = 0; i < globalSymCount; i++) { 214 ELFSymbol symbol = globalSymbols.get(i); 215 Pointer address = symbol.getAddress(); 216 address.copyBytesTo(sectionDataArray, entrySize, (localSymCount + i) * entrySize); 217 } 218 219 return sectionDataArray; 220 } 221 222 private static int getELFTypeOf(Symbol sym) { 223 Kind kind = sym.getKind(); 224 if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) { 225 return ELF.STT_FUNC; 226 } else if (kind == Symbol.Kind.OBJECT) { 227 return ELF.STT_OBJECT; 228 } 229 return ELF.STT_NOTYPE; 230 } 231 232 private static int getELFBindOf(Symbol sym) { 233 Binding binding = sym.getBinding(); 234 if (binding == Symbol.Binding.GLOBAL) { 235 return ELF.STB_GLOBAL; 236 } 237 return ELF.STB_LOCAL; 238 } 239 240 /** 241 * Construct ELF relocation section data from BinaryContainer object's relocation tables. 242 * 243 * @param relocationTable 244 */ 245 private void createELFRelocationTables(Map<Symbol, List<Relocation>> relocationTable) { 246 /* 247 * For each of the symbols with associated relocation records, create an ELF relocation 248 * entry. 249 */ 250 for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) { 251 List<Relocation> relocs = entry.getValue(); 252 Symbol symbol = entry.getKey(); 253 254 for (Relocation reloc : relocs) { 255 createRelocation(symbol, reloc); 256 } 257 } 258 259 for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) { 260 createRelocation(entry.getKey(), entry.getValue()); 261 } 262 } 263 264 private void createRelocation(Symbol symbol, Relocation reloc) { 265 RelocType relocType = reloc.getType(); 266 int elfRelocType = getELFRelocationType(relocType); 267 268 switch (relocType) { 269 case FOREIGN_CALL_DIRECT: 270 case JAVA_CALL_DIRECT: 271 case STUB_CALL_DIRECT: 272 case FOREIGN_CALL_INDIRECT_GOT: { 273 // Create relocation entry 274 int addend = -4; // Size in bytes of the patch location 275 // Relocation should be applied at the location after call operand 276 int offset = reloc.getOffset() + reloc.getSize() + addend; 277 elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol()); 278 break; 279 } 280 case FOREIGN_CALL_DIRECT_FAR: { 281 // Create relocation entry 282 int addend = -8; // Size in bytes of the patch location 283 // Relocation should be applied at the location after call operand 284 // 10 = 2 (jmp [r]) + 8 (imm64) 285 int offset = reloc.getOffset() + reloc.getSize() + addend - 2; 286 elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol()); 287 break; 288 } 289 case FOREIGN_CALL_INDIRECT: 290 case JAVA_CALL_INDIRECT: 291 case STUB_CALL_INDIRECT: { 292 // Do nothing. 293 break; 294 } 295 case EXTERNAL_DATA_REFERENCE_FAR: { 296 // Create relocation entry 297 int addend = -4; // Size of 32-bit address of the GOT 298 /* 299 * Relocation should be applied before the test instruction to the move instruction. 300 * reloc.getOffset() points to the test instruction after the instruction that loads 301 * the address of polling page. So set the offset appropriately. 302 */ 303 int offset = reloc.getOffset() + addend; 304 elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol()); 305 break; 306 } 307 case METASPACE_GOT_REFERENCE: 308 case EXTERNAL_PLT_TO_GOT: 309 case STATIC_STUB_TO_STATIC_METHOD: 310 case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: { 311 int addend = -4; // Size of 32-bit address of the GOT 312 /* 313 * Relocation should be applied before the test instruction to the move instruction. 314 * reloc.getOffset() points to the test instruction after the instruction that loads 315 * the address of polling page. So set the offset appropriately. 316 */ 317 int offset = reloc.getOffset() + addend; 318 elfContainer.createELFRelocationEntry(reloc.getSection(), offset, elfRelocType, addend, symbol.getElfSymbol()); 319 break; 320 } 321 case EXTERNAL_GOT_TO_PLT: 322 case LOADTIME_ADDRESS: { 323 // this is load time relocations 324 elfContainer.createELFRelocationEntry(reloc.getSection(), reloc.getOffset(), elfRelocType, 0, symbol.getElfSymbol()); 325 break; 326 } 327 default: 328 throw new InternalError("Unhandled relocation type: " + relocType); 329 } 330 } 331 332 // TODO: Populate the mapping of RelocType to ELF relocation types 333 private static int getELFRelocationType(RelocType relocType) { 334 int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH 335 switch (JNIELFTargetInfo.getELFArch()) { 336 case ELF.EM_X64_64: 337 // Return R_X86_64_* entries based on relocType 338 if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { 339 elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PLT32; 340 } else if (relocType == RelocType.STUB_CALL_DIRECT) { 341 elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32; 342 } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) { 343 elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64; 344 } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) { 345 elfRelocType = JNIELFRelocation.X86_64.R_X86_64_NONE; 346 } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) { 347 elfRelocType = JNIELFRelocation.X86_64.R_X86_64_GOTPCREL; 348 } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD || 349 relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) { 350 elfRelocType = JNIELFRelocation.X86_64.R_X86_64_PC32; 351 } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) { 352 elfRelocType = JNIELFRelocation.X86_64.R_X86_64_64; 353 } else { 354 assert false : "Unhandled relocation type: " + relocType; 355 } 356 break; 357 default: 358 System.out.println("Relocation Type mapping: Unhandled architecture"); 359 } 360 return elfRelocType; 361 } 362 363 private void createAllRelocationSections(ELFContainer symtab) { 364 for (Map.Entry<ELFContainer, ArrayList<Pointer>> entry : elfContainer.getRelocTables().entrySet()) { 365 createRelocationSection(entry.getKey(), entry.getValue(), symtab); 366 } 367 } 368 369 private void createRelocationSection(ELFContainer container, ArrayList<Pointer> relocations, ELFContainer symtab) { 370 String secName = container.getContainerName(); 371 int entrySize = JNIELFTargetInfo.sizeOfRelocEntry(); 372 int numEntries = relocations.size(); 373 byte[] sectionDataBytes = new byte[numEntries * entrySize]; 374 375 for (int index = 0; index < relocations.size(); index++) { 376 Pointer entry = relocations.get(index); 377 entry.copyBytesTo(sectionDataBytes, entrySize, index * entrySize); 378 } 379 String fullSecName; 380 // If relocDat is non-null create section 381 if (sectionDataBytes.length > 0) { 382 int scnType; 383 Elf_Type dataType; 384 if (JNIELFTargetInfo.createReloca() == 0) { 385 scnType = ELF.SHT_REL; 386 dataType = Elf_Type.ELF_T_REL; 387 fullSecName = ".rel" + secName; 388 } else { 389 scnType = ELF.SHT_RELA; 390 dataType = Elf_Type.ELF_T_RELA; 391 fullSecName = ".rela" + secName; 392 } 393 // assert compareBytes(relocData.toByteArray(), sectionDataBytes) : "******* Bad array 394 // copy"; 395 // sh_link holds the index of section header of symbol table associated with this 396 // relocation table. 397 // sh_info holds the index of section header to which this relocation table applies 398 // to. 399 elfContainer.createSection(fullSecName, sectionDataBytes, dataType, 8, scnType, ELF.SHF_ALLOC, symtab.getSectionId(), container.getSectionId()); 400 } 401 } 402 403 private static class SymTabELFContainer implements ELFContainer { 404 private final int symTabSectionIndex; 405 406 public SymTabELFContainer(int symTabSectionIndex) { 407 this.symTabSectionIndex = symTabSectionIndex; 408 } 409 410 @Override 411 public String getContainerName() { 412 return ".symtab"; 413 } 414 415 @Override 416 public int getSectionId() { 417 return symTabSectionIndex; 418 } 419 } 420 } | 1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.tools.jaotc.binformat.elf; 25 26 import java.io.IOException; 27 import java.nio.charset.StandardCharsets; 28 import java.util.ArrayList; 29 import java.util.Collection; 30 import java.util.List; 31 import java.util.Map; 32 33 import jdk.tools.jaotc.binformat.Container; 34 import jdk.tools.jaotc.binformat.BinaryContainer; 35 import jdk.tools.jaotc.binformat.ByteContainer; 36 import jdk.tools.jaotc.binformat.CodeContainer; 37 import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; 38 import jdk.tools.jaotc.binformat.Relocation; 39 import jdk.tools.jaotc.binformat.Relocation.RelocType; 40 import jdk.tools.jaotc.binformat.Symbol; 41 import jdk.tools.jaotc.binformat.NativeSymbol; 42 import jdk.tools.jaotc.binformat.Symbol.Binding; 43 import jdk.tools.jaotc.binformat.Symbol.Kind; 44 45 import jdk.tools.jaotc.binformat.elf.Elf; 46 import jdk.tools.jaotc.binformat.elf.ElfSymbol; 47 import jdk.tools.jaotc.binformat.elf.ElfTargetInfo; 48 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; 49 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr; 50 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym; 51 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rel; 52 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela; 53 54 public class JELFRelocObject { 55 56 private final BinaryContainer binContainer; 57 58 private final ElfContainer elfContainer; 59 60 private final int segmentSize; 61 62 public JELFRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) { 63 this.binContainer = binContainer; 64 this.elfContainer = new ElfContainer(outputFileName, aotVersion); 65 this.segmentSize = binContainer.getCodeSegmentSize(); 66 } 67 68 private ElfSection createByteSection(ArrayList<ElfSection>sections, 69 String sectName, 70 byte [] scnData, 71 boolean hasRelocs, 72 int scnFlags, 73 int scnType) { 74 75 ElfSection sect = new ElfSection(sectName, 76 scnData, 77 scnFlags, 78 scnType, 79 hasRelocs, 80 sections.size()); 81 // Add this section to our list 82 sections.add(sect); 83 84 return (sect); 85 } 86 87 private void createByteSection(ArrayList<ElfSection>sections, 88 ByteContainer c, int scnFlags) { 89 ElfSection sect; 90 boolean hasRelocs = c.hasRelocations(); 91 byte[] scnData = c.getByteArray(); 92 93 int scnType = Elf64_Shdr.SHT_PROGBITS; 94 boolean zeros = hasRelocs; 95 if (zeros) { 96 for (byte b : scnData) { 97 if (b != 0) { 98 zeros = false; 99 break; 100 } 101 } 102 if (zeros) { 103 scnType = Elf64_Shdr.SHT_NOBITS; 104 } 105 } 106 107 sect = createByteSection(sections, c.getContainerName(), 108 scnData, hasRelocs, 109 scnFlags, scnType); 110 c.setSectionId(sect.getSectionId()); 111 } 112 113 private void createCodeSection(ArrayList<ElfSection>sections, CodeContainer c) { 114 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR); 115 } 116 117 private void createReadOnlySection(ArrayList<ElfSection>sections, ReadOnlyDataContainer c) { 118 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC); 119 } 120 121 private void createReadWriteSection(ArrayList<ElfSection>sections, ByteContainer c) { 122 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_WRITE); 123 } 124 125 /** 126 * Create an ELF relocatable object 127 * 128 * @param relocationTable 129 * @param symbols 130 * @throws IOException throws {@code IOException} as a result of file system access failures. 131 */ 132 public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException { 133 // Allocate ELF Header 134 ElfHeader eh = new ElfHeader(); 135 136 ArrayList<ElfSection> sections = new ArrayList<ElfSection>(); 137 138 // Create the null section 139 createByteSection(sections, null, null, false, 0, 0); 140 141 // Create text section 142 createCodeSection(sections, binContainer.getCodeContainer()); 143 createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer()); 144 createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); 145 createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); 146 createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); 147 createReadWriteSection(sections, binContainer.getMetaspaceGotContainer()); 148 createReadWriteSection(sections, binContainer.getMetadataGotContainer()); 149 createReadWriteSection(sections, binContainer.getMethodStateContainer()); 150 createReadWriteSection(sections, binContainer.getOopGotContainer()); 151 createReadWriteSection(sections, binContainer.getMethodMetadataContainer()); 152 createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); 153 createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); 154 createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); 155 createReadOnlySection(sections, binContainer.getConstantDataContainer()); 156 createReadOnlySection(sections, binContainer.getConfigContainer()); 157 158 // createExternalLinkage(); 159 160 createCodeSection(sections, binContainer.getExtLinkageContainer()); 161 createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); 162 163 // Get ELF symbol data from BinaryContainer object's symbol tables 164 ElfSymtab symtab = createELFSymbolTables(sections, symbols); 165 166 // Create string table section and symbol table sections in 167 // that order since symtab section needs to set the index of 168 // strtab in sh_link field 169 ElfSection strTabSection = createByteSection(sections, 170 ".strtab", 171 symtab.getStrtabArray(), 172 false, 173 0, 174 Elf64_Shdr.SHT_STRTAB); 175 176 // Now create .symtab section with the symtab data constructed. 177 // On Linux, sh_link of symtab contains the index of string table 178 // its symbols reference and sh_info contains the index of first 179 // non-local symbol 180 ElfSection symTabSection = createByteSection(sections, 181 ".symtab", 182 symtab.getSymtabArray(), 183 false, 184 0, 185 Elf64_Shdr.SHT_SYMTAB); 186 symTabSection.setLink(strTabSection.getSectionId()); 187 symTabSection.setInfo(symtab.getNumLocalSyms()); 188 189 ElfRelocTable elfRelocTable = createElfRelocTable(sections, 190 relocationTable); 191 192 createElfRelocSections(sections, elfRelocTable, symTabSection.getSectionId()); 193 194 // Now, finally, after creating all sections, create shstrtab section 195 ElfSection shStrTabSection = createByteSection(sections, 196 ".shstrtab", 197 null, 198 false, 199 0, 200 Elf64_Shdr.SHT_STRTAB); 201 eh.setSectionStrNdx(shStrTabSection.getSectionId()); 202 203 // Update all section offsets and the Elf header section offset 204 // Write the Header followed by the contents of each section 205 // and then the section structures (section table). 206 int file_offset = Elf64_Ehdr.totalsize; 207 208 // and round it up 209 file_offset = (file_offset + (sections.get(1).getDataAlign()-1)) & 210 ~((sections.get(1).getDataAlign()-1)); 211 212 // Calc file offsets for section data skipping null section 213 for (int i = 1; i < sections.size(); i++) { 214 ElfSection sect = sections.get(i); 215 file_offset = (file_offset + (sect.getDataAlign()-1)) & 216 ~((sect.getDataAlign()-1)); 217 sect.setOffset(file_offset); 218 file_offset += sect.getSize(); 219 } 220 221 // Align the section table 222 file_offset = (file_offset + (ElfSection.getShdrAlign()-1)) & 223 ~((ElfSection.getShdrAlign()-1)); 224 225 // Update the Elf Header with the offset of the first Elf64_Shdr 226 // and the number of sections. 227 eh.setSectionOff(file_offset); 228 eh.setSectionNum(sections.size()); 229 230 // Write out the Header 231 elfContainer.writeBytes(eh.getArray()); 232 233 // Write out each section contents skipping null section 234 for (int i = 1; i < sections.size(); i++) { 235 ElfSection sect = sections.get(i); 236 elfContainer.writeBytes(sect.getDataArray(), sect.getDataAlign()); 237 } 238 239 // Write out the section table 240 for (int i = 0; i < sections.size(); i++) { 241 ElfSection sect = sections.get(i); 242 elfContainer.writeBytes(sect.getArray(), ElfSection.getShdrAlign()); 243 } 244 245 elfContainer.close(); 246 } 247 /** 248 * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF 249 * symbol table and ELF symbol table are created from BinaryContainer's symbol info. 250 * 251 * @param symbols 252 */ 253 private ElfSymtab createELFSymbolTables(ArrayList<ElfSection> sections, Collection<Symbol> symbols) { 254 ElfSymtab symtab = new ElfSymtab(); 255 256 // First, create the initial null symbol. This is a local symbol. 257 symtab.addSymbolEntry("", (byte)0, (byte)0, Elf64_Shdr.SHN_UNDEF, 0, 0); 258 259 // Now create ELF symbol entries for all symbols. 260 for (Symbol symbol : symbols) { 261 // Get the index of section this symbol is defined in. 262 int secHdrIndex = symbol.getSection().getSectionId(); 263 ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize()); 264 symbol.setNativeSymbol((NativeSymbol)elfSymbol); 265 } 266 return (symtab); 267 } 268 269 private static byte getELFTypeOf(Symbol sym) { 270 Kind kind = sym.getKind(); 271 if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) { 272 return Elf64_Sym.STT_FUNC; 273 } else if (kind == Symbol.Kind.OBJECT) { 274 return Elf64_Sym.STT_OBJECT; 275 } 276 return Elf64_Sym.STT_NOTYPE; 277 } 278 279 private static byte getELFBindOf(Symbol sym) { 280 Binding binding = sym.getBinding(); 281 if (binding == Symbol.Binding.GLOBAL) { 282 return Elf64_Sym.STB_GLOBAL; 283 } 284 return Elf64_Sym.STB_LOCAL; 285 } 286 287 /** 288 * Construct a Elf relocation table from BinaryContainer object's relocation tables. 289 * 290 * @param sections 291 * @param relocationTable 292 */ 293 private ElfRelocTable createElfRelocTable(ArrayList<ElfSection> sections, 294 Map<Symbol, List<Relocation>> relocationTable) { 295 296 ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size()); 297 /* 298 * For each of the symbols with associated relocation records, create a Elf relocation 299 * entry. 300 */ 301 for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) { 302 List<Relocation> relocs = entry.getValue(); 303 Symbol symbol = entry.getKey(); 304 305 for (Relocation reloc : relocs) { 306 createRelocation(symbol, reloc, elfRelocTable); 307 } 308 } 309 310 for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) { 311 createRelocation(entry.getKey(), entry.getValue(), elfRelocTable); 312 } 313 314 return (elfRelocTable); 315 } 316 317 private void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) { 318 RelocType relocType = reloc.getType(); 319 320 int elfRelocType = getELFRelocationType(relocType); 321 ElfSymbol sym = (ElfSymbol)symbol.getNativeSymbol(); 322 int symno = sym.getIndex(); 323 int sectindex = reloc.getSection().getSectionId(); 324 int offset = reloc.getOffset(); 325 int addend = 0; 326 327 switch (relocType) { 328 case FOREIGN_CALL_DIRECT: 329 case JAVA_CALL_DIRECT: 330 case STUB_CALL_DIRECT: 331 case FOREIGN_CALL_INDIRECT_GOT: { 332 // Create relocation entry 333 // System.out.println("getELFRelocationType: PLT relocation type using X86_64_RELOC_BRANCH"); 334 addend = -4; // Size in bytes of the patch location 335 // Relocation should be applied at the location after call operand 336 offset = offset + reloc.getSize() + addend; 337 break; 338 } 339 case FOREIGN_CALL_DIRECT_FAR: { 340 // Create relocation entry 341 addend = -8; // Size in bytes of the patch location 342 // Relocation should be applied at the location after call operand 343 // 10 = 2 (jmp [r]) + 8 (imm64) 344 offset = offset + reloc.getSize() + addend - 2; 345 break; 346 } 347 case FOREIGN_CALL_INDIRECT: 348 case JAVA_CALL_INDIRECT: 349 case STUB_CALL_INDIRECT: { 350 // Do nothing. 351 return; 352 } 353 case EXTERNAL_DATA_REFERENCE_FAR: { 354 // Create relocation entry 355 addend = -4; // Size of 32-bit address of the GOT 356 /* 357 * Relocation should be applied before the test instruction to the move instruction. 358 * offset points to the test instruction after the instruction that loads 359 * the address of polling page. So set the offset appropriately. 360 */ 361 offset = offset + addend; 362 break; 363 } 364 case METASPACE_GOT_REFERENCE: 365 case EXTERNAL_PLT_TO_GOT: 366 case STATIC_STUB_TO_STATIC_METHOD: 367 case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: { 368 addend = -4; // Size of 32-bit address of the GOT 369 /* 370 * Relocation should be applied before the test instruction to 371 * the move instruction. reloc.getOffset() points to the 372 * test instruction after the instruction that loads the 373 * address of polling page. So set the offset appropriately. 374 */ 375 offset = offset + addend; 376 break; 377 } 378 case EXTERNAL_GOT_TO_PLT: 379 case LOADTIME_ADDRESS: { 380 // this is load time relocations 381 break; 382 } 383 default: 384 throw new InternalError("Unhandled relocation type: " + relocType); 385 } 386 elfRelocTable.createRelocationEntry(sectindex, offset, symno, elfRelocType, addend); 387 } 388 389 private static int getELFRelocationType(RelocType relocType) { 390 int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH 391 switch (ElfTargetInfo.getElfArch()) { 392 case Elf64_Ehdr.EM_X86_64: 393 // Return R_X86_64_* entries based on relocType 394 if (relocType == RelocType.FOREIGN_CALL_DIRECT || 395 relocType == RelocType.JAVA_CALL_DIRECT || 396 relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { 397 elfRelocType = Elf64_Rela.R_X86_64_PLT32; 398 } else if (relocType == RelocType.STUB_CALL_DIRECT) { 399 elfRelocType = Elf64_Rela.R_X86_64_PC32; 400 } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) { 401 elfRelocType = Elf64_Rela.R_X86_64_64; 402 } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || 403 relocType == RelocType.JAVA_CALL_INDIRECT || 404 relocType == RelocType.STUB_CALL_INDIRECT) { 405 elfRelocType = Elf64_Rela.R_X86_64_NONE; 406 } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) { 407 elfRelocType = Elf64_Rela.R_X86_64_GOTPCREL; 408 } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || 409 relocType == RelocType.EXTERNAL_PLT_TO_GOT || 410 relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD || 411 relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) { 412 elfRelocType = Elf64_Rela.R_X86_64_PC32; 413 } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || 414 relocType == RelocType.LOADTIME_ADDRESS) { 415 elfRelocType = Elf64_Rela.R_X86_64_64; 416 } else { 417 assert false : "Unhandled relocation type: " + relocType; 418 } 419 break; 420 default: 421 System.out.println("Relocation Type mapping: Unhandled architecture"); 422 } 423 return elfRelocType; 424 } 425 426 private void createElfRelocSections(ArrayList<ElfSection> sections, 427 ElfRelocTable elfRelocTable, 428 int symtabsectidx) { 429 430 // Grab count before we create new sections 431 int count = sections.size(); 432 433 for (int i = 0; i < count; i++) { 434 if (elfRelocTable.getNumRelocs(i) > 0) { 435 ElfSection sect = sections.get(i); 436 String relname = ".rela" + sect.getName(); 437 ElfSection relocSection = createByteSection(sections, 438 relname, 439 elfRelocTable.getRelocData(i), 440 false, 441 0, 442 Elf64_Shdr.SHT_RELA); 443 relocSection.setLink(symtabsectidx); 444 relocSection.setInfo(sect.getSectionId()); 445 } 446 } 447 } 448 } |