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