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 align, 73 int scnFlags, 74 int scnType) { 75 76 ElfSection sect = new ElfSection(sectName, 77 scnData, 78 scnFlags, 79 scnType, 80 hasRelocs, 81 align, 82 sections.size()); 83 // Add this section to our list 84 sections.add(sect); 85 86 return (sect); 87 } 88 89 private void createByteSection(ArrayList<ElfSection>sections, 90 ByteContainer c, int scnFlags) { 91 ElfSection sect; 92 boolean hasRelocs = c.hasRelocations(); 93 byte[] scnData = c.getByteArray(); 94 95 int scnType = Elf64_Shdr.SHT_PROGBITS; 96 boolean zeros = !hasRelocs; 97 if (zeros) { 98 for (byte b : scnData) { 99 if (b != 0) { 100 zeros = false; 101 break; 102 } 103 } 104 if (zeros) { 105 scnType = Elf64_Shdr.SHT_NOBITS; 106 } 107 } 108 109 sect = createByteSection(sections, c.getContainerName(), 110 scnData, hasRelocs, segmentSize, 111 scnFlags, scnType); 112 c.setSectionId(sect.getSectionId()); 113 } 114 115 private void createCodeSection(ArrayList<ElfSection>sections, CodeContainer c) { 116 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR); 117 } 118 119 private void createReadOnlySection(ArrayList<ElfSection>sections, ReadOnlyDataContainer c) { 120 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC); 121 } 122 123 private void createReadWriteSection(ArrayList<ElfSection>sections, ByteContainer c) { 124 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_WRITE); 125 } 126 127 /** 128 * Create an ELF relocatable object 129 * 130 * @param relocationTable 131 * @param symbols 132 * @throws IOException throws {@code IOException} as a result of file system access failures. 133 */ 134 public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException { 135 // Allocate ELF Header 136 ElfHeader eh = new ElfHeader(); 137 138 ArrayList<ElfSection> sections = new ArrayList<ElfSection>(); 139 140 // Create the null section 141 createByteSection(sections, null, null, false, 1, 0, 0); 142 143 // Create text section 144 createCodeSection(sections, binContainer.getCodeContainer()); 145 createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer()); 146 createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); 147 createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); 148 createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); 149 createReadWriteSection(sections, binContainer.getMetaspaceGotContainer()); 150 createReadWriteSection(sections, binContainer.getMetadataGotContainer()); 151 createReadWriteSection(sections, binContainer.getMethodStateContainer()); 152 createReadWriteSection(sections, binContainer.getOopGotContainer()); 153 createReadWriteSection(sections, binContainer.getMethodMetadataContainer()); 154 createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); 155 createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); 156 createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); 157 createReadOnlySection(sections, binContainer.getConstantDataContainer()); 158 createReadOnlySection(sections, binContainer.getConfigContainer()); 159 160 // createExternalLinkage(); 161 162 createCodeSection(sections, binContainer.getExtLinkageContainer()); 163 createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); 164 165 // Get ELF symbol data from BinaryContainer object's symbol tables 166 ElfSymtab symtab = createELFSymbolTables(sections, symbols); 167 168 // Create string table section and symbol table sections in 169 // that order since symtab section needs to set the index of 170 // strtab in sh_link field 171 ElfSection strTabSection = createByteSection(sections, 172 ".strtab", 173 symtab.getStrtabArray(), 174 false, 175 1, 176 0, 177 Elf64_Shdr.SHT_STRTAB); 178 179 // Now create .symtab section with the symtab data constructed. 180 // On Linux, sh_link of symtab contains the index of string table 181 // its symbols reference and sh_info contains the index of first 182 // non-local symbol 183 ElfSection symTabSection = createByteSection(sections, 184 ".symtab", 185 symtab.getSymtabArray(), 186 false, 187 8, 188 0, 189 Elf64_Shdr.SHT_SYMTAB); 190 symTabSection.setLink(strTabSection.getSectionId()); 191 symTabSection.setInfo(symtab.getNumLocalSyms()); 192 193 ElfRelocTable elfRelocTable = createElfRelocTable(sections, 194 relocationTable); 195 196 createElfRelocSections(sections, elfRelocTable, symTabSection.getSectionId()); 197 198 // Now, finally, after creating all sections, create shstrtab section 199 ElfSection shStrTabSection = createByteSection(sections, 200 ".shstrtab", 201 null, 202 false, 203 1, 204 0, 205 Elf64_Shdr.SHT_STRTAB); 206 eh.setSectionStrNdx(shStrTabSection.getSectionId()); 207 208 // Update all section offsets and the Elf header section offset 209 // Write the Header followed by the contents of each section 210 // and then the section structures (section table). 211 int file_offset = Elf64_Ehdr.totalsize; 212 213 // and round it up 214 file_offset = (file_offset + (sections.get(1).getDataAlign()-1)) & 215 ~((sections.get(1).getDataAlign()-1)); 216 217 // Calc file offsets for section data skipping null section 218 for (int i = 1; i < sections.size(); i++) { 219 ElfSection sect = sections.get(i); 220 file_offset = (file_offset + (sect.getDataAlign()-1)) & 221 ~((sect.getDataAlign()-1)); 222 sect.setOffset(file_offset); 223 file_offset += sect.getSize(); 224 } 225 226 // Align the section table 227 file_offset = (file_offset + (ElfSection.getShdrAlign()-1)) & 228 ~((ElfSection.getShdrAlign()-1)); 229 230 // Update the Elf Header with the offset of the first Elf64_Shdr 231 // and the number of sections. 232 eh.setSectionOff(file_offset); 233 eh.setSectionNum(sections.size()); 234 235 // Write out the Header 236 elfContainer.writeBytes(eh.getArray()); 237 238 // Write out each section contents skipping null section 239 for (int i = 1; i < sections.size(); i++) { 240 ElfSection sect = sections.get(i); 241 elfContainer.writeBytes(sect.getDataArray(), sect.getDataAlign()); 242 } 243 244 // Write out the section table 245 for (int i = 0; i < sections.size(); i++) { 246 ElfSection sect = sections.get(i); 247 elfContainer.writeBytes(sect.getArray(), ElfSection.getShdrAlign()); 248 } 249 250 elfContainer.close(); 251 } 252 /** 253 * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF 254 * symbol table and ELF symbol table are created from BinaryContainer's symbol info. 255 * 256 * @param symbols 257 */ 258 private ElfSymtab createELFSymbolTables(ArrayList<ElfSection> sections, Collection<Symbol> symbols) { 259 ElfSymtab symtab = new ElfSymtab(); 260 261 // First, create the initial null symbol. This is a local symbol. 262 symtab.addSymbolEntry("", (byte)0, (byte)0, Elf64_Shdr.SHN_UNDEF, 0, 0); 263 264 // Now create ELF symbol entries for all symbols. 265 for (Symbol symbol : symbols) { 266 // Get the index of section this symbol is defined in. 267 int secHdrIndex = symbol.getSection().getSectionId(); 268 ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize()); 269 symbol.setNativeSymbol((NativeSymbol)elfSymbol); 270 } 271 return (symtab); 272 } 273 274 private static byte getELFTypeOf(Symbol sym) { 275 Kind kind = sym.getKind(); 276 if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) { 277 return Elf64_Sym.STT_FUNC; 278 } else if (kind == Symbol.Kind.OBJECT) { 279 return Elf64_Sym.STT_OBJECT; 280 } 281 return Elf64_Sym.STT_NOTYPE; 282 } 283 284 private static byte getELFBindOf(Symbol sym) { 285 Binding binding = sym.getBinding(); 286 if (binding == Symbol.Binding.GLOBAL) { 287 return Elf64_Sym.STB_GLOBAL; 288 } 289 return Elf64_Sym.STB_LOCAL; 290 } 291 292 /** 293 * Construct a Elf relocation table from BinaryContainer object's relocation tables. 294 * 295 * @param sections 296 * @param relocationTable 297 */ 298 private ElfRelocTable createElfRelocTable(ArrayList<ElfSection> sections, 299 Map<Symbol, List<Relocation>> relocationTable) { 300 301 ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size()); 302 /* 303 * For each of the symbols with associated relocation records, create a Elf relocation 304 * entry. 305 */ 306 for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) { 307 List<Relocation> relocs = entry.getValue(); 308 Symbol symbol = entry.getKey(); 309 310 for (Relocation reloc : relocs) { 311 createRelocation(symbol, reloc, elfRelocTable); 312 } 313 } 314 315 for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) { 316 createRelocation(entry.getKey(), entry.getValue(), elfRelocTable); 317 } 318 319 return (elfRelocTable); 320 } 321 322 private void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable) { 323 RelocType relocType = reloc.getType(); 324 325 int elfRelocType = getELFRelocationType(relocType); 326 ElfSymbol sym = (ElfSymbol)symbol.getNativeSymbol(); 327 int symno = sym.getIndex(); 328 int sectindex = reloc.getSection().getSectionId(); 329 int offset = reloc.getOffset(); 330 int addend = 0; 331 332 switch (relocType) { 333 case FOREIGN_CALL_DIRECT: 334 case JAVA_CALL_DIRECT: 335 case STUB_CALL_DIRECT: 336 case FOREIGN_CALL_INDIRECT_GOT: { 337 // Create relocation entry 338 // System.out.println("getELFRelocationType: PLT relocation type using X86_64_RELOC_BRANCH"); 339 addend = -4; // Size in bytes of the patch location 340 // Relocation should be applied at the location after call operand 341 offset = offset + reloc.getSize() + addend; 342 break; 343 } 344 case FOREIGN_CALL_DIRECT_FAR: { 345 // Create relocation entry 346 addend = -8; // Size in bytes of the patch location 347 // Relocation should be applied at the location after call operand 348 // 10 = 2 (jmp [r]) + 8 (imm64) 349 offset = offset + reloc.getSize() + addend - 2; 350 break; 351 } 352 case FOREIGN_CALL_INDIRECT: 353 case JAVA_CALL_INDIRECT: 354 case STUB_CALL_INDIRECT: { 355 // Do nothing. 356 return; 357 } 358 case EXTERNAL_DATA_REFERENCE_FAR: { 359 // Create relocation entry 360 addend = -4; // Size of 32-bit address of the GOT 361 /* 362 * Relocation should be applied before the test instruction to the move instruction. 363 * offset points to the test instruction after the instruction that loads 364 * the address of polling page. So set the offset appropriately. 365 */ 366 offset = offset + addend; 367 break; 368 } 369 case METASPACE_GOT_REFERENCE: 370 case EXTERNAL_PLT_TO_GOT: 371 case STATIC_STUB_TO_STATIC_METHOD: 372 case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: { 373 addend = -4; // Size of 32-bit address of the GOT 374 /* 375 * Relocation should be applied before the test instruction to 376 * the move instruction. reloc.getOffset() points to the 377 * test instruction after the instruction that loads the 378 * address of polling page. So set the offset appropriately. 379 */ 380 offset = offset + addend; 381 break; 382 } 383 case EXTERNAL_GOT_TO_PLT: 384 case LOADTIME_ADDRESS: { 385 // this is load time relocations 386 break; 387 } 388 default: 389 throw new InternalError("Unhandled relocation type: " + relocType); 390 } 391 elfRelocTable.createRelocationEntry(sectindex, offset, symno, elfRelocType, addend); 392 } 393 394 private static int getELFRelocationType(RelocType relocType) { 395 int elfRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH 396 switch (ElfTargetInfo.getElfArch()) { 397 case Elf64_Ehdr.EM_X86_64: 398 // Return R_X86_64_* entries based on relocType 399 if (relocType == RelocType.FOREIGN_CALL_DIRECT || 400 relocType == RelocType.JAVA_CALL_DIRECT || 401 relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { 402 elfRelocType = Elf64_Rela.R_X86_64_PLT32; 403 } else if (relocType == RelocType.STUB_CALL_DIRECT) { 404 elfRelocType = Elf64_Rela.R_X86_64_PC32; 405 } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) { 406 elfRelocType = Elf64_Rela.R_X86_64_64; 407 } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || 408 relocType == RelocType.JAVA_CALL_INDIRECT || 409 relocType == RelocType.STUB_CALL_INDIRECT) { 410 elfRelocType = Elf64_Rela.R_X86_64_NONE; 411 } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) { 412 elfRelocType = Elf64_Rela.R_X86_64_GOTPCREL; 413 } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || 414 relocType == RelocType.EXTERNAL_PLT_TO_GOT || 415 relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD || 416 relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) { 417 elfRelocType = Elf64_Rela.R_X86_64_PC32; 418 } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || 419 relocType == RelocType.LOADTIME_ADDRESS) { 420 elfRelocType = Elf64_Rela.R_X86_64_64; 421 } else { 422 assert false : "Unhandled relocation type: " + relocType; 423 } 424 break; 425 default: 426 System.out.println("Relocation Type mapping: Unhandled architecture"); 427 } 428 return elfRelocType; 429 } 430 431 private void createElfRelocSections(ArrayList<ElfSection> sections, 432 ElfRelocTable elfRelocTable, 433 int symtabsectidx) { 434 435 // Grab count before we create new sections 436 int count = sections.size(); 437 438 for (int i = 0; i < count; i++) { 439 if (elfRelocTable.getNumRelocs(i) > 0) { 440 ElfSection sect = sections.get(i); 441 String relname = ".rela" + sect.getName(); 442 ElfSection relocSection = createByteSection(sections, 443 relname, 444 elfRelocTable.getRelocData(i), 445 false, 446 8, 447 0, 448 Elf64_Shdr.SHT_RELA); 449 relocSection.setLink(symtabsectidx); 450 relocSection.setInfo(sect.getSectionId()); 451 } 452 } 453 } 454 }