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.pecoff; 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.pecoff.PECoff; 46 import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol; 47 import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo; 48 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER; 49 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER; 50 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL; 51 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION; 52 53 public class JPECoffRelocObject { 54 55 private final BinaryContainer binContainer; 56 57 private final PECoffContainer pecoffContainer; 58 59 private final int segmentSize; 60 61 public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName, String aotVersion) { 62 this.binContainer = binContainer; 63 this.pecoffContainer = new PECoffContainer(outputFileName, aotVersion); 64 this.segmentSize = binContainer.getCodeSegmentSize(); 65 if (segmentSize != 64) { 66 System.out.println("binContainer alignment size not 64 bytes, update JPECoffRelocObject"); 67 } 68 } 69 70 private PECoffSection createByteSection(ArrayList<PECoffSection>sections, 71 String sectName, 72 byte [] scnData, 73 boolean hasRelocs, 74 int scnFlags) { 75 76 PECoffSection sect = new PECoffSection(sectName, 77 scnData, 78 scnFlags, 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<PECoffSection>sections, 88 ByteContainer c, int scnFlags) { 89 PECoffSection sect; 90 boolean hasRelocs = c.hasRelocations(); 91 byte[] scnData = c.getByteArray(); 92 93 sect = createByteSection(sections, c.getContainerName(), 94 scnData, hasRelocs, 95 scnFlags); 96 97 c.setSectionId(sect.getSectionId()); 98 } 99 100 private void createCodeSection(ArrayList<PECoffSection>sections, CodeContainer c) { 101 createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | 102 IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE | 103 IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES | 104 IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE); 105 } 106 107 private void createReadOnlySection(ArrayList<PECoffSection>sections, ReadOnlyDataContainer c) { 108 createByteSection(sections, c, IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | 109 IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES | 110 IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA); 111 } 112 113 private void createReadWriteSection(ArrayList<PECoffSection>sections, ByteContainer c) { 114 int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | 115 IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE | 116 IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_64BYTES; 117 118 if (c.getByteArray().length > 0) 119 scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA; 120 else 121 scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_UNINITIALIZED_DATA; 122 123 createByteSection(sections, c, scnFlags); 124 } 125 126 /** 127 * Create an PECoff relocatable object 128 * 129 * @param relocationTable 130 * @param symbols 131 * @throws IOException throws {@code IOException} as a result of file system access failures. 132 */ 133 public void createPECoffRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException { 134 ArrayList<PECoffSection> sections = new ArrayList<PECoffSection>(); 135 136 // Create text section 137 createCodeSection(sections, binContainer.getCodeContainer()); 138 createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer()); 139 createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); 140 createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); 141 createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); 142 createReadWriteSection(sections, binContainer.getMetaspaceGotContainer()); 143 createReadWriteSection(sections, binContainer.getMetadataGotContainer()); 144 createReadWriteSection(sections, binContainer.getMethodStateContainer()); 145 createReadWriteSection(sections, binContainer.getOopGotContainer()); 146 createReadWriteSection(sections, binContainer.getMethodMetadataContainer()); 147 createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); 148 createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); 149 createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); 150 createReadOnlySection(sections, binContainer.getConstantDataContainer()); 151 createReadOnlySection(sections, binContainer.getConfigContainer()); 152 153 // createExternalLinkage(); 154 155 createCodeSection(sections, binContainer.getExtLinkageContainer()); 156 createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); 157 158 // Allocate PECoff Header 159 PECoffHeader header = new PECoffHeader(); 160 161 // Get PECoff symbol data from BinaryContainer object's symbol tables 162 PECoffSymtab symtab = createPECoffSymbolTables(sections, symbols); 163 164 // Add Linker Directives Section 165 createByteSection(sections, ".drectve", 166 symtab.getDirectiveArray(), false, 167 IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO | 168 IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE | 169 IMAGE_SECTION_HEADER.IMAGE_SCN_ALIGN_1BYTES); 170 171 // Create the Relocation Tables 172 PECoffRelocTable pecoffRelocs = createPECoffRelocTable(sections, relocationTable); 173 174 // File Output Order 175 // 176 // HEADER (Need address of Symbol Table + symbol count) 177 // SECTIONS (Need pointer to Section Data, Relocation Table) 178 // DIRECTIVES 179 // SYMBOL TABLE 180 // SYMBOLS 181 // SECTION DATA 182 // RELOCATION TABLE 183 184 // Calculate Offset for Symbol table 185 int file_offset = IMAGE_FILE_HEADER.totalsize + 186 (IMAGE_SECTION_HEADER.totalsize*sections.size()); 187 188 // Update Header fields 189 header.setSectionCount(sections.size()); 190 header.setSymbolCount(symtab.getSymtabCount()); 191 header.setSymbolOff(file_offset); 192 193 // Calculate file offset for first section 194 file_offset += ((symtab.getSymtabCount() * IMAGE_SYMBOL.totalsize) + 195 symtab.getStrtabSize()); 196 // And round it up 197 file_offset = (file_offset + (sections.get(0).getDataAlign()-1)) & 198 ~((sections.get(0).getDataAlign()-1)); 199 200 // Calc file offsets for section data 201 for (int i = 0; i < sections.size(); i++) { 202 PECoffSection sect = sections.get(i); 203 file_offset = (file_offset + (sect.getDataAlign()-1)) & 204 ~((sect.getDataAlign()-1)); 205 sect.setOffset(file_offset); 206 file_offset += sect.getSize(); 207 } 208 209 // Update relocation sizing information in each section 210 for (int i = 0; i < sections.size(); i++) { 211 PECoffSection sect = sections.get(i); 212 if (sect.hasRelocations()) { 213 int nreloc = pecoffRelocs.getNumRelocs(i); 214 sect.setReloff(file_offset); 215 sect.setRelcount(nreloc); 216 // extended relocations add an addition entry 217 if (nreloc > 0xFFFF) nreloc++; 218 file_offset += (nreloc * IMAGE_RELOCATION.totalsize); 219 } 220 } 221 222 // Write out the Header 223 pecoffContainer.writeBytes(header.getArray()); 224 225 // Write out the section table 226 for (int i = 0; i < sections.size(); i++) { 227 PECoffSection sect = sections.get(i); 228 pecoffContainer.writeBytes(sect.getArray(), PECoffSection.getShdrAlign()); 229 } 230 231 // Write out the symbol table and string table 232 pecoffContainer.writeBytes(symtab.getSymtabArray(), 4); 233 pecoffContainer.writeBytes(symtab.getStrtabArray(), 1); 234 235 // Write out each section contents 236 for (int i = 0; i < sections.size(); i++) { 237 PECoffSection sect = sections.get(i); 238 pecoffContainer.writeBytes(sect.getDataArray(), sect.getDataAlign()); 239 } 240 241 // Write out Relocation Tables 242 for (int i = 0; i < sections.size(); i++) { 243 if (pecoffRelocs.getNumRelocs(i) > 0) { 244 pecoffContainer.writeBytes(pecoffRelocs.getRelocData(i)); 245 } 246 } 247 pecoffContainer.close(); 248 } 249 250 /** 251 * Construct PECoff symbol data from BinaryContainer object's symbol tables. Both dynamic PECoff 252 * symbol table and PECoff symbol table are created from BinaryContainer's symbol info. 253 * 254 * @param symbols 255 */ 256 private PECoffSymtab createPECoffSymbolTables(ArrayList<PECoffSection> sections, Collection<Symbol> symbols) { 257 PECoffSymtab symtab = new PECoffSymtab(); 258 259 // First, create the initial null symbol. This is a local symbol. 260 // symtab.addSymbolEntry("", (byte)0, (byte)0, (byte)0, 0, 0); 261 262 // Now create PECoff symbol entries for all symbols. 263 for (Symbol symbol : symbols) { 264 // Get the index of section this symbol is defined in. 265 int secHdrIndex = symbol.getSection().getSectionId(); 266 PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte)secHdrIndex, symbol.getOffset(), symbol.getSize()); 267 symbol.setNativeSymbol((NativeSymbol)pecoffSymbol); 268 } 269 return (symtab); 270 } 271 272 private static byte getPECoffTypeOf(Symbol sym) { 273 Kind kind = sym.getKind(); 274 if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) { 275 return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION; 276 } 277 return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_NONE; 278 } 279 280 private static byte getPECoffClassOf(Symbol sym) { 281 Binding binding = sym.getBinding(); 282 if (binding == Symbol.Binding.GLOBAL) { 283 return IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL; 284 } 285 return IMAGE_SYMBOL.IMAGE_SYM_CLASS_STATIC; 286 } 287 288 /** 289 * Construct a PECoff relocation table from BinaryContainer object's relocation tables. 290 * 291 * @param sections 292 * @param relocationTable 293 */ 294 private PECoffRelocTable createPECoffRelocTable(ArrayList<PECoffSection> sections, 295 Map<Symbol, List<Relocation>> relocationTable) { 296 297 PECoffRelocTable pecoffRelocTable = new PECoffRelocTable(sections.size()); 298 /* 299 * For each of the symbols with associated relocation records, create a PECoff relocation 300 * entry. 301 */ 302 for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) { 303 List<Relocation> relocs = entry.getValue(); 304 Symbol symbol = entry.getKey(); 305 306 for (Relocation reloc : relocs) { 307 createRelocation(symbol, reloc, pecoffRelocTable); 308 } 309 } 310 311 for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) { 312 createRelocation(entry.getKey(), entry.getValue(), pecoffRelocTable); 313 } 314 315 return (pecoffRelocTable); 316 } 317 318 private void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) { 319 RelocType relocType = reloc.getType(); 320 321 int pecoffRelocType = getPECoffRelocationType(relocType); 322 PECoffSymbol sym = (PECoffSymbol)symbol.getNativeSymbol(); 323 int symno = sym.getIndex(); 324 int sectindex = reloc.getSection().getSectionId(); 325 int offset = reloc.getOffset(); 326 int addend = 0; 327 328 switch (relocType) { 329 case FOREIGN_CALL_DIRECT: 330 case JAVA_CALL_DIRECT: 331 case STUB_CALL_DIRECT: 332 case FOREIGN_CALL_INDIRECT_GOT: { 333 // Create relocation entry 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 pecoffRelocTable.createRelocationEntry(sectindex, offset, symno, pecoffRelocType); 387 } 388 389 // Return IMAGE_RELOCATION Type based on relocType 390 private static int getPECoffRelocationType(RelocType relocType) { 391 int pecoffRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH 392 switch (PECoffTargetInfo.getPECoffArch()) { 393 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: 394 if (relocType == RelocType.FOREIGN_CALL_DIRECT || 395 relocType == RelocType.JAVA_CALL_DIRECT || 396 relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { 397 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; 398 } else if (relocType == RelocType.STUB_CALL_DIRECT) { 399 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; 400 } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) { 401 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64; 402 } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || 403 relocType == RelocType.JAVA_CALL_INDIRECT || 404 relocType == RelocType.STUB_CALL_INDIRECT) { 405 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ABSOLUTE; 406 } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) { 407 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; 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 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; 413 } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || 414 relocType == RelocType.LOADTIME_ADDRESS) { 415 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64; 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 pecoffRelocType; 424 } 425 } | 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.pecoff; 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.pecoff.PECoffSymbol; 43 import jdk.tools.jaotc.binformat.pecoff.PECoffTargetInfo; 44 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_FILE_HEADER; 45 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SECTION_HEADER; 46 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL; 47 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_RELOCATION; 48 49 public class JPECoffRelocObject { 50 51 private final BinaryContainer binContainer; 52 53 private final PECoffContainer pecoffContainer; 54 55 private final int sectionAlignment; 56 57 public JPECoffRelocObject(BinaryContainer binContainer, String outputFileName) { 58 this.binContainer = binContainer; 59 this.pecoffContainer = new PECoffContainer(outputFileName); 60 this.sectionAlignment = binContainer.getCodeSegmentSize(); 61 } 62 63 private static PECoffSection createByteSection(ArrayList<PECoffSection> sections, String sectName, byte[] scnData, 64 boolean hasRelocs, int scnFlags, int sectAlign) { 65 66 PECoffSection sect = new PECoffSection(sectName, scnData, scnFlags, sectAlign, hasRelocs, sections.size()); 67 // Add this section to our list 68 sections.add(sect); 69 70 return (sect); 71 } 72 73 private static void createByteSection(ArrayList<PECoffSection> sections, ByteContainer c, int scnFlags, int sectAlign) { 74 PECoffSection sect; 75 boolean hasRelocs = c.hasRelocations(); 76 byte[] scnData = c.getByteArray(); 77 78 sect = createByteSection(sections, c.getContainerName(), scnData, hasRelocs, scnFlags, sectAlign); 79 80 c.setSectionId(sect.getSectionId()); 81 } 82 83 private void createCodeSection(ArrayList<PECoffSection> sections, CodeContainer c) { 84 int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE | IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE; 85 createByteSection(sections, c, scnFlags, sectionAlignment); 86 } 87 88 private void createReadOnlySection(ArrayList<PECoffSection> sections, ReadOnlyDataContainer c) { 89 int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA; 90 createByteSection(sections, c, scnFlags, sectionAlignment); 91 } 92 93 private void createReadWriteSection(ArrayList<PECoffSection> sections, ByteContainer c) { 94 int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ | IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE; 95 96 if (c.getByteArray().length > 0) { 97 scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA; 98 } else { 99 scnFlags |= IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_UNINITIALIZED_DATA; 100 } 101 createByteSection(sections, c, scnFlags, sectionAlignment); 102 } 103 104 /** 105 * Create an PECoff relocatable object 106 * 107 * @param relocationTable 108 * @param symbols 109 * @throws IOException throws {@code IOException} as a result of file system access failures. 110 */ 111 public void createPECoffRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException { 112 ArrayList<PECoffSection> sections = new ArrayList<>(); 113 114 // Create text section 115 createCodeSection(sections, binContainer.getCodeContainer()); 116 createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer()); 117 createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); 118 createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); 119 createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); 120 createReadOnlySection(sections, binContainer.getMethodMetadataContainer()); 121 createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); 122 createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); 123 createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); 124 createReadOnlySection(sections, binContainer.getConstantDataContainer()); 125 createReadOnlySection(sections, binContainer.getConfigContainer()); 126 createReadWriteSection(sections, binContainer.getKlassesGotContainer()); 127 createReadWriteSection(sections, binContainer.getCountersGotContainer()); 128 createReadWriteSection(sections, binContainer.getMetadataGotContainer()); 129 createReadWriteSection(sections, binContainer.getMethodStateContainer()); 130 createReadWriteSection(sections, binContainer.getOopGotContainer()); 131 createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); 132 133 // Allocate PECoff Header 134 PECoffHeader header = new PECoffHeader(); 135 136 // Get PECoff symbol data from BinaryContainer object's symbol tables 137 PECoffSymtab symtab = createPECoffSymbolTables(symbols); 138 139 // Add Linker Directives Section 140 int scnFlags = IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO | IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE; 141 createByteSection(sections, ".drectve", symtab.getDirectiveArray(), false, scnFlags, 1 /* 1 byte alignment */); 142 143 // Create the Relocation Tables 144 PECoffRelocTable pecoffRelocs = createPECoffRelocTable(sections, relocationTable); 145 146 // File Output Order 147 // 148 // HEADER (Need address of Symbol Table + symbol count) 149 // SECTIONS (Need pointer to Section Data, Relocation Table) 150 // DIRECTIVES 151 // SYMBOL TABLE 152 // SYMBOLS 153 // SECTION DATA 154 // RELOCATION TABLE 155 156 // Calculate Offset for Symbol table 157 int file_offset = IMAGE_FILE_HEADER.totalsize + 158 (IMAGE_SECTION_HEADER.totalsize * sections.size()); 159 160 // Update Header fields 161 header.setSectionCount(sections.size()); 162 header.setSymbolCount(symtab.getSymtabCount()); 163 header.setSymbolOff(file_offset); 164 165 // Calculate file offset for first section 166 file_offset += ((symtab.getSymtabCount() * IMAGE_SYMBOL.totalsize) + 167 symtab.getStrtabSize()); 168 // And round it up 169 file_offset = (file_offset + (sections.get(0).getDataAlign() - 1)) & 170 ~((sections.get(0).getDataAlign() - 1)); 171 172 // Calc file offsets for section data 173 for (int i = 0; i < sections.size(); i++) { 174 PECoffSection sect = sections.get(i); 175 file_offset = (file_offset + (sect.getDataAlign() - 1)) & 176 ~((sect.getDataAlign() - 1)); 177 sect.setOffset(file_offset); 178 file_offset += sect.getSize(); 179 } 180 181 // Update relocation sizing information in each section 182 for (int i = 0; i < sections.size(); i++) { 183 PECoffSection sect = sections.get(i); 184 if (sect.hasRelocations()) { 185 int nreloc = pecoffRelocs.getNumRelocs(i); 186 sect.setReloff(file_offset); 187 sect.setRelcount(nreloc); 188 // extended relocations add an addition entry 189 if (nreloc > 0xFFFF) { 190 nreloc++; 191 } 192 file_offset += (nreloc * IMAGE_RELOCATION.totalsize); 193 } 194 } 195 196 // Write out the Header 197 pecoffContainer.writeBytes(header.getArray()); 198 199 // Write out the section table 200 for (int i = 0; i < sections.size(); i++) { 201 PECoffSection sect = sections.get(i); 202 pecoffContainer.writeBytes(sect.getArray(), PECoffSection.getShdrAlign()); 203 } 204 205 // Write out the symbol table and string table 206 pecoffContainer.writeBytes(symtab.getSymtabArray(), 4); 207 pecoffContainer.writeBytes(symtab.getStrtabArray(), 1); 208 209 // Write out each section contents 210 for (int i = 0; i < sections.size(); i++) { 211 PECoffSection sect = sections.get(i); 212 pecoffContainer.writeBytes(sect.getDataArray(), sect.getDataAlign()); 213 } 214 215 // Write out Relocation Tables 216 for (int i = 0; i < sections.size(); i++) { 217 if (pecoffRelocs.getNumRelocs(i) > 0) { 218 pecoffContainer.writeBytes(pecoffRelocs.getRelocData(i)); 219 } 220 } 221 pecoffContainer.close(); 222 } 223 224 /** 225 * Construct PECoff symbol data from BinaryContainer object's symbol tables. Both dynamic PECoff 226 * symbol table and PECoff symbol table are created from BinaryContainer's symbol info. 227 * 228 * @param symbols 229 */ 230 private static PECoffSymtab createPECoffSymbolTables(Collection<Symbol> symbols) { 231 PECoffSymtab symtab = new PECoffSymtab(); 232 233 // First, create the initial null symbol. This is a local symbol. 234 // symtab.addSymbolEntry("", (byte)0, (byte)0, (byte)0, 0, 0); 235 236 // Now create PECoff symbol entries for all symbols. 237 for (Symbol symbol : symbols) { 238 // Get the index of section this symbol is defined in. 239 int secHdrIndex = symbol.getSection().getSectionId(); 240 PECoffSymbol pecoffSymbol = symtab.addSymbolEntry(symbol.getName(), getPECoffTypeOf(symbol), getPECoffClassOf(symbol), (byte) secHdrIndex, symbol.getOffset()); 241 symbol.setNativeSymbol(pecoffSymbol); 242 } 243 return (symtab); 244 } 245 246 private static byte getPECoffTypeOf(Symbol sym) { 247 Kind kind = sym.getKind(); 248 if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) { 249 return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION; 250 } 251 return IMAGE_SYMBOL.IMAGE_SYM_DTYPE_NONE; 252 } 253 254 private static byte getPECoffClassOf(Symbol sym) { 255 Binding binding = sym.getBinding(); 256 if (binding == Symbol.Binding.GLOBAL) { 257 return IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL; 258 } 259 return IMAGE_SYMBOL.IMAGE_SYM_CLASS_STATIC; 260 } 261 262 /** 263 * Construct a PECoff relocation table from BinaryContainer object's relocation tables. 264 * 265 * @param sections 266 * @param relocationTable 267 */ 268 private PECoffRelocTable createPECoffRelocTable(ArrayList<PECoffSection> sections, Map<Symbol, List<Relocation>> relocationTable) { 269 270 PECoffRelocTable pecoffRelocTable = new PECoffRelocTable(sections.size()); 271 /* 272 * For each of the symbols with associated relocation records, create a PECoff relocation entry. 273 */ 274 for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) { 275 List<Relocation> relocs = entry.getValue(); 276 Symbol symbol = entry.getKey(); 277 278 for (Relocation reloc : relocs) { 279 createRelocation(symbol, reloc, pecoffRelocTable); 280 } 281 } 282 283 for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) { 284 createRelocation(entry.getKey(), entry.getValue(), pecoffRelocTable); 285 } 286 287 return (pecoffRelocTable); 288 } 289 290 private static void createRelocation(Symbol symbol, Relocation reloc, PECoffRelocTable pecoffRelocTable) { 291 RelocType relocType = reloc.getType(); 292 293 int pecoffRelocType = getPECoffRelocationType(relocType); 294 PECoffSymbol sym = (PECoffSymbol) symbol.getNativeSymbol(); 295 int symno = sym.getIndex(); 296 int sectindex = reloc.getSection().getSectionId(); 297 int offset = reloc.getOffset(); 298 int addend = 0; 299 300 switch (relocType) { 301 case JAVA_CALL_DIRECT: 302 case STUB_CALL_DIRECT: 303 case FOREIGN_CALL_INDIRECT_GOT: { 304 // Create relocation entry 305 addend = -4; // Size in bytes of the patch location 306 // Relocation should be applied at the location after call operand 307 offset = offset + reloc.getSize() + addend; 308 break; 309 } 310 case JAVA_CALL_INDIRECT: { 311 // Do nothing. 312 return; 313 } 314 case METASPACE_GOT_REFERENCE: 315 case EXTERNAL_PLT_TO_GOT: { 316 addend = -4; // Size of 32-bit address of the GOT 317 /* 318 * Relocation should be applied before the test instruction to the move instruction. 319 * reloc.getOffset() points to the test instruction after the instruction that loads the address of 320 * polling page. So set the offset appropriately. 321 */ 322 offset = offset + addend; 323 break; 324 } 325 case EXTERNAL_GOT_TO_PLT: { 326 // this is load time relocations 327 break; 328 } 329 default: 330 throw new InternalError("Unhandled relocation type: " + relocType); 331 } 332 pecoffRelocTable.createRelocationEntry(sectindex, offset, symno, pecoffRelocType); 333 } 334 335 // Return IMAGE_RELOCATION Type based on relocType 336 private static int getPECoffRelocationType(RelocType relocType) { 337 int pecoffRelocType = 0; // R_<ARCH>_NONE if #define'd to 0 for all values of ARCH 338 switch (PECoffTargetInfo.getPECoffArch()) { 339 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: 340 if (relocType == RelocType.JAVA_CALL_DIRECT || 341 relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { 342 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; 343 } else if (relocType == RelocType.STUB_CALL_DIRECT) { 344 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; 345 } else if (relocType == RelocType.JAVA_CALL_INDIRECT) { 346 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ABSOLUTE; 347 } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || 348 relocType == RelocType.EXTERNAL_PLT_TO_GOT) { 349 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_REL32; 350 } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) { 351 pecoffRelocType = IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64; 352 } else { 353 assert false : "Unhandled relocation type: " + relocType; 354 } 355 break; 356 default: 357 System.out.println("Relocation Type mapping: Unhandled architecture"); 358 } 359 return pecoffRelocType; 360 } 361 } |