36 * Relocation entries 37 * Symbol table 38 * 39 */ 40 41 package jdk.tools.jaotc.binformat.macho; 42 43 import java.io.IOException; 44 import java.util.ArrayList; 45 import java.util.Collection; 46 import java.util.List; 47 import java.util.Map; 48 49 import jdk.tools.jaotc.binformat.BinaryContainer; 50 import jdk.tools.jaotc.binformat.ByteContainer; 51 import jdk.tools.jaotc.binformat.CodeContainer; 52 import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; 53 import jdk.tools.jaotc.binformat.Relocation; 54 import jdk.tools.jaotc.binformat.Relocation.RelocType; 55 import jdk.tools.jaotc.binformat.Symbol; 56 import jdk.tools.jaotc.binformat.NativeSymbol; 57 import jdk.tools.jaotc.binformat.Symbol.Binding; 58 import jdk.tools.jaotc.binformat.Symbol.Kind; 59 60 import jdk.tools.jaotc.binformat.macho.MachO; 61 import jdk.tools.jaotc.binformat.macho.MachO.section_64; 62 import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64; 63 import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64; 64 import jdk.tools.jaotc.binformat.macho.MachO.version_min_command; 65 import jdk.tools.jaotc.binformat.macho.MachO.symtab_command; 66 import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command; 67 import jdk.tools.jaotc.binformat.macho.MachO.nlist_64; 68 import jdk.tools.jaotc.binformat.macho.MachO.reloc_info; 69 import jdk.tools.jaotc.binformat.macho.MachOContainer; 70 import jdk.tools.jaotc.binformat.macho.MachOTargetInfo; 71 import jdk.tools.jaotc.binformat.macho.MachOSymtab; 72 import jdk.tools.jaotc.binformat.macho.MachORelocTable; 73 74 public class JMachORelocObject { 75 76 private final BinaryContainer binContainer; 77 78 private final MachOContainer machoContainer; 79 80 private final int segmentSize; 81 82 public JMachORelocObject(BinaryContainer binContainer, String outputFileName) { 83 this.binContainer = binContainer; 84 this.machoContainer = new MachOContainer(outputFileName); 85 this.segmentSize = binContainer.getCodeSegmentSize(); 86 } 87 88 private void createByteSection(ArrayList<MachOSection>sections, 89 ByteContainer c, String sectName, String segName, int scnFlags) { 90 91 if (c.getByteArray().length == 0) { 92 // System.out.println("Skipping creation of " + sectName + " section, no data\n"); 93 } 94 95 MachOSection sect = new MachOSection(sectName, 96 segName, 97 c.getByteArray(), 98 scnFlags, 99 c.hasRelocations(), 100 segmentSize); 101 // Add this section to our list 102 sections.add(sect); 103 104 // Record the section Id (0 relative) 105 c.setSectionId(sections.size()-1); 106 107 // TODO: Clear out code section data to allow for GC 108 // c.clear(); 109 } 110 111 private void createCodeSection(ArrayList<MachOSection>sections, CodeContainer c) { 112 createByteSection(sections, c, /*c.getContainerName()*/ "__text", "__TEXT", 113 section_64.S_ATTR_PURE_INSTRUCTIONS| 114 section_64.S_ATTR_SOME_INSTRUCTIONS); 115 } 116 117 private void createReadOnlySection(ArrayList<MachOSection>sections, ReadOnlyDataContainer c) { 118 createByteSection(sections, c, c.getContainerName(), "__TEXT", 119 section_64.S_ATTR_SOME_INSTRUCTIONS); 120 } 121 122 private void createReadWriteSection(ArrayList<MachOSection>sections, ByteContainer c) { 123 createByteSection(sections, c, c.getContainerName(), "__DATA", section_64.S_REGULAR); 124 } 125 126 /** 127 * Create an MachO 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 createMachORelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException { 134 // Allocate MachO Header 135 // with 4 load commands 136 // LC_SEGMENT_64 137 // LC_VERSION_MIN_MACOSX 138 // LC_SYMTAB 139 // LC_DYSYMTAB 140 141 MachOHeader mh = new MachOHeader(); 142 143 ArrayList<MachOSection> sections = new ArrayList<MachOSection>(); 144 145 // Create Sections contained in the main Segment LC_SEGMENT_64 146 147 createCodeSection(sections, binContainer.getCodeContainer()); 148 createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer()); 149 createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); 150 createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); 151 createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); 152 createReadWriteSection(sections, binContainer.getMetaspaceGotContainer()); 153 createReadWriteSection(sections, binContainer.getMetadataGotContainer()); 154 createReadWriteSection(sections, binContainer.getMethodStateContainer()); 155 createReadWriteSection(sections, binContainer.getOopGotContainer()); 156 createReadWriteSection(sections, binContainer.getMethodMetadataContainer()); 157 createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); 158 createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); 159 createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); 160 createReadOnlySection(sections, binContainer.getConstantDataContainer()); 161 createReadOnlySection(sections, binContainer.getConfigContainer()); 162 163 // createExternalLinkage(); 164 165 createCodeSection(sections, binContainer.getExtLinkageContainer()); 166 createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); 167 // Update the Header sizeofcmds size. 168 // This doesn't include the Header struct size 169 mh.setCmdSizes(4, segment_command_64.totalsize + 170 (section_64.totalsize * sections.size()) + 171 version_min_command.totalsize + 172 symtab_command.totalsize + 173 dysymtab_command.totalsize); 174 175 // Initialize file offset for data past commands 176 int file_offset = mach_header_64.totalsize + mh.getCmdSize(); 177 // and round it up 178 file_offset = (file_offset + (sections.get(0).getAlign()-1)) & ~((sections.get(0).getAlign()-1)); 179 long address = 0; 180 int segment_offset = file_offset; 181 182 for (int i = 0; i < sections.size(); i++) { 183 MachOSection sect = sections.get(i); 184 file_offset = (file_offset + (sect.getAlign()-1)) & ~((sect.getAlign()-1)); 185 address = (address + (sect.getAlign()-1)) & ~((sect.getAlign()-1)); 186 sect.setOffset(file_offset); 187 sect.setAddr(address); 188 file_offset += sect.getSize(); 189 address += sect.getSize(); 190 } 191 192 // File size for Segment data 193 int segment_size = file_offset - segment_offset; 194 195 // Create the LC_SEGMENT_64 Segment which contains the MachOSections 196 MachOSegment seg = new MachOSegment(segment_command_64.totalsize + 197 (section_64.totalsize * sections.size()), 198 segment_offset, 199 segment_size, 200 sections.size()); 201 202 203 MachOVersion vers = new MachOVersion(); 204 205 // Get symbol data from BinaryContainer object's symbol tables 206 MachOSymtab symtab = createMachOSymbolTables(sections, symbols); 207 208 // Create LC_DYSYMTAB command 209 MachODySymtab dysymtab = new MachODySymtab(symtab.getNumLocalSyms(), 210 symtab.getNumGlobalSyms(), 211 symtab.getNumUndefSyms()); 212 213 // Create the Relocation Tables 214 MachORelocTable machORelocs = createMachORelocTable(sections, relocationTable, symtab); 215 // Calculate file offset for relocation data 216 file_offset = (file_offset + (machORelocs.getAlign()-1)) & ~((machORelocs.getAlign()-1)); 217 218 // Update relocation sizing information in each section 219 for (int i = 0; i < sections.size(); i++) { 220 MachOSection sect = sections.get(i); 221 if (sect.hasRelocations()) { 222 int nreloc = machORelocs.getNumRelocs(i); 223 sect.setReloff(file_offset); 224 sect.setRelcount(nreloc); 225 file_offset += (nreloc * reloc_info.totalsize); 226 } 227 } 228 229 // Calculate and set file offset for symbol table data 230 file_offset = (file_offset + (symtab.getAlign()-1)) & ~((symtab.getAlign()-1)); 231 symtab.setOffset(file_offset); 232 233 234 // Write Out Header 235 machoContainer.writeBytes(mh.getArray()); 236 // Write out first Segment 237 machoContainer.writeBytes(seg.getArray()); 238 // Write out sections within first Segment 239 for (int i = 0; i < sections.size(); i++) { 240 MachOSection sect = sections.get(i); 241 machoContainer.writeBytes(sect.getArray()); 242 } 243 244 // Write out LC_VERSION_MIN_MACOSX command 245 machoContainer.writeBytes(vers.getArray()); 246 247 // Write out LC_SYMTAB command 248 symtab.calcSizes(); 249 machoContainer.writeBytes(symtab.getCmdArray()); 250 251 // Write out LC_DYSYMTAB command 252 machoContainer.writeBytes(dysymtab.getArray()); 253 254 // Write out data associated with each Section 255 for (int i = 0; i < sections.size(); i++) { 256 MachOSection sect = sections.get(i); 257 machoContainer.writeBytes(sect.getDataArray(), sect.getAlign()); 258 } 259 260 // Write out the relocation tables for all sections 261 for (int i = 0; i < sections.size(); i++) { 262 if (machORelocs.getNumRelocs(i) > 0) 263 machoContainer.writeBytes(machORelocs.getRelocData(i), machORelocs.getAlign()); 264 } 265 266 // Write out data associated with LC_SYMTAB 267 machoContainer.writeBytes(symtab.getDataArray(), symtab.getAlign()); 268 269 machoContainer.close(); 270 } 271 272 /** 273 * Construct MachO symbol data from BinaryContainer object's symbol tables. Both dynamic MachO 274 * symbol table and MachO symbol table are created from BinaryContainer's symbol info. 275 * 276 * @param symbols 277 * @param symtab 278 */ 279 private MachOSymtab createMachOSymbolTables(ArrayList<MachOSection>sections, 280 Collection<Symbol> symbols) { 281 MachOSymtab symtab = new MachOSymtab(); 282 // First, create the initial null symbol. This is a local symbol. 283 symtab.addSymbolEntry("", (byte)nlist_64.N_UNDF, (byte)0, (long)0); 284 285 // Now create MachO symbol entries for all symbols. 286 for (Symbol symbol : symbols) { 287 int sectionId = symbol.getSection().getSectionId(); 288 289 // Symbol offsets are relative to the section memory addr 290 long sectionAddr = sections.get(sectionId).getAddr(); 291 292 MachOSymbol machoSymbol = symtab.addSymbolEntry(symbol.getName(), 293 getMachOTypeOf(symbol), 294 (byte)sectionId, 295 symbol.getOffset() + sectionAddr); 296 symbol.setNativeSymbol((NativeSymbol)machoSymbol); 297 } 298 299 // Now that all symbols are enterred, update the 300 // symbol indexes. This is necessary since they will 301 // be reordered based on local, global and undefined. 302 symtab.updateIndexes(); 303 304 return (symtab); 305 } 306 307 private static byte getMachOTypeOf(Symbol sym) { 308 Kind kind = sym.getKind(); 309 byte type = nlist_64.N_UNDF; 310 311 // Global or Local 312 if (sym.getBinding() == Symbol.Binding.GLOBAL) 313 type = nlist_64.N_EXT; 314 315 // If Function or Data, add section type 316 if (kind == Symbol.Kind.NATIVE_FUNCTION || 317 kind == Symbol.Kind.JAVA_FUNCTION || 318 kind == Symbol.Kind.OBJECT) { 319 type |= (nlist_64.N_SECT); 320 } 321 322 return (type); 323 } 324 325 /** 326 * Construct a MachO relocation table from BinaryContainer object's relocation tables. 327 * 328 * @param sections 329 * @param relocationTable 330 * @param symtab 331 */ 332 private MachORelocTable createMachORelocTable(ArrayList<MachOSection> sections, 333 Map<Symbol, List<Relocation>> relocationTable, 334 MachOSymtab symtab) { 335 336 MachORelocTable machORelocTable = new MachORelocTable(sections.size()); 337 /* 338 * For each of the symbols with associated relocation records, create a MachO relocation 339 * entry. 340 */ 341 for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) { 342 List<Relocation> relocs = entry.getValue(); 343 Symbol symbol = entry.getKey(); 344 345 for (Relocation reloc : relocs) { 346 createRelocation(symbol, reloc, machORelocTable); 347 } 348 } 349 350 for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) { 351 createRelocation(entry.getKey(), entry.getValue(), machORelocTable); 352 } 353 354 return (machORelocTable); 355 } 356 357 private void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) { 358 RelocType relocType = reloc.getType(); 359 360 int machORelocType = getMachORelocationType(relocType); 361 MachOSymbol sym = (MachOSymbol)symbol.getNativeSymbol(); 362 int symno = sym.getIndex(); 363 int sectindex = reloc.getSection().getSectionId(); 364 int offset = reloc.getOffset(); 365 int pcrel = 0; 366 int length = 0; 367 int isextern = 1; 368 369 /* 370 System.out.println("reloctype: " + relocType + " size is " + 371 reloc.getSize() + " offset is " + offset + 372 " Section Index is " + (sectindex) + 373 " Symbol Index is " + symno + 374 " Symbol Name is " + symbol.getName() + "\n"); 375 */ 376 377 switch (relocType) { 378 case FOREIGN_CALL_DIRECT: 379 case JAVA_CALL_DIRECT: 380 case STUB_CALL_DIRECT: 381 case FOREIGN_CALL_INDIRECT_GOT: { 382 // Create relocation entry 383 // System.out.println("getMachORelocationType: PLT relocation type using X86_64_RELOC_BRANCH"); 384 int addend = -4; // Size in bytes of the patch location 385 // Relocation should be applied at the location after call operand 386 offset = offset + reloc.getSize() + addend; 387 pcrel = 1; length = 2; 388 break; 389 } 390 case FOREIGN_CALL_DIRECT_FAR: { 391 // Create relocation entry 392 int addend = -8; // Size in bytes of the patch location 393 // Relocation should be applied at the location after call operand 394 // 10 = 2 (jmp [r]) + 8 (imm64) 395 offset = offset + reloc.getSize() + addend - 2; 396 pcrel = 0; length = 3; 397 break; 398 } 399 case FOREIGN_CALL_INDIRECT: 400 case JAVA_CALL_INDIRECT: 401 case STUB_CALL_INDIRECT: { 402 // Do nothing. 403 return; 404 } 405 case EXTERNAL_DATA_REFERENCE_FAR: { 406 // Create relocation entry 407 int addend = -4; // Size of 32-bit address of the GOT 408 /* 409 * Relocation should be applied before the test instruction to the move instruction. 410 * offset points to the test instruction after the instruction that loads 411 * the address of polling page. So set the offset appropriately. 412 */ 413 offset = offset + addend; 414 pcrel = 0; length = 2; 415 break; 416 } 417 case METASPACE_GOT_REFERENCE: 418 case EXTERNAL_PLT_TO_GOT: 419 case STATIC_STUB_TO_STATIC_METHOD: 420 case STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT: { 421 int addend = -4; // Size of 32-bit address of the GOT 422 /* 423 * Relocation should be applied before the test instruction to 424 * the move instruction. reloc.getOffset() points to the 425 * test instruction after the instruction that loads the 426 * address of polling page. So set the offset appropriately. 427 */ 428 offset = offset + addend; 429 pcrel = 1; length = 2; 430 break; 431 } 432 case EXTERNAL_GOT_TO_PLT: 433 case LOADTIME_ADDRESS: { 434 // this is load time relocations 435 pcrel = 0; length = 3; 436 break; 437 } 438 default: 439 throw new InternalError("Unhandled relocation type: " + relocType); 440 } 441 machORelocTable.createRelocationEntry(sectindex, offset, symno, 442 pcrel, length, isextern, 443 machORelocType); 444 } 445 446 private static int getMachORelocationType(RelocType relocType) { 447 int machORelocType = 0; 448 switch (MachOTargetInfo.getMachOArch()) { 449 case mach_header_64.CPU_TYPE_X86_64: 450 // Return X86_64_RELOC_* entries based on relocType 451 if (relocType == RelocType.FOREIGN_CALL_DIRECT || relocType == RelocType.JAVA_CALL_DIRECT || relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { 452 machORelocType = reloc_info.X86_64_RELOC_BRANCH; 453 } else if (relocType == RelocType.STUB_CALL_DIRECT) { 454 machORelocType = reloc_info.X86_64_RELOC_BRANCH; 455 } else if (relocType == RelocType.FOREIGN_CALL_DIRECT_FAR) { 456 machORelocType = reloc_info.X86_64_RELOC_UNSIGNED; 457 } else if (relocType == RelocType.FOREIGN_CALL_INDIRECT || relocType == RelocType.JAVA_CALL_INDIRECT || relocType == RelocType.STUB_CALL_INDIRECT) { 458 machORelocType = reloc_info.X86_64_RELOC_NONE; 459 } else if ((relocType == RelocType.EXTERNAL_DATA_REFERENCE_FAR)) { 460 machORelocType = reloc_info.X86_64_RELOC_GOT; 461 } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || relocType == RelocType.EXTERNAL_PLT_TO_GOT || relocType == RelocType.STATIC_STUB_TO_STATIC_METHOD || 462 relocType == RelocType.STATIC_STUB_TO_HOTSPOT_LINKAGE_GOT) { 463 machORelocType = reloc_info.X86_64_RELOC_BRANCH; 464 } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT || relocType == RelocType.LOADTIME_ADDRESS) { 465 machORelocType = reloc_info.X86_64_RELOC_UNSIGNED; 466 } else { 467 assert false : "Unhandled relocation type: " + relocType; 468 } 469 break; 470 default: 471 System.out.println("Relocation Type mapping: Unhandled architecture"); 472 } 473 return machORelocType; 474 } 475 } | 36 * Relocation entries 37 * Symbol table 38 * 39 */ 40 41 package jdk.tools.jaotc.binformat.macho; 42 43 import java.io.IOException; 44 import java.util.ArrayList; 45 import java.util.Collection; 46 import java.util.List; 47 import java.util.Map; 48 49 import jdk.tools.jaotc.binformat.BinaryContainer; 50 import jdk.tools.jaotc.binformat.ByteContainer; 51 import jdk.tools.jaotc.binformat.CodeContainer; 52 import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; 53 import jdk.tools.jaotc.binformat.Relocation; 54 import jdk.tools.jaotc.binformat.Relocation.RelocType; 55 import jdk.tools.jaotc.binformat.Symbol; 56 import jdk.tools.jaotc.binformat.Symbol.Kind; 57 58 import jdk.tools.jaotc.binformat.macho.MachO.section_64; 59 import jdk.tools.jaotc.binformat.macho.MachO.mach_header_64; 60 import jdk.tools.jaotc.binformat.macho.MachO.segment_command_64; 61 import jdk.tools.jaotc.binformat.macho.MachO.version_min_command; 62 import jdk.tools.jaotc.binformat.macho.MachO.symtab_command; 63 import jdk.tools.jaotc.binformat.macho.MachO.dysymtab_command; 64 import jdk.tools.jaotc.binformat.macho.MachO.nlist_64; 65 import jdk.tools.jaotc.binformat.macho.MachO.reloc_info; 66 import jdk.tools.jaotc.binformat.macho.MachOContainer; 67 import jdk.tools.jaotc.binformat.macho.MachOTargetInfo; 68 import jdk.tools.jaotc.binformat.macho.MachOSymtab; 69 import jdk.tools.jaotc.binformat.macho.MachORelocTable; 70 71 public class JMachORelocObject { 72 73 private final BinaryContainer binContainer; 74 75 private final MachOContainer machoContainer; 76 77 private final int segmentSize; 78 79 public JMachORelocObject(BinaryContainer binContainer, String outputFileName) { 80 this.binContainer = binContainer; 81 this.machoContainer = new MachOContainer(outputFileName); 82 this.segmentSize = binContainer.getCodeSegmentSize(); 83 } 84 85 private void createByteSection(ArrayList<MachOSection> sections, 86 ByteContainer c, String sectName, String segName, int scnFlags) { 87 88 if (c.getByteArray().length == 0) { 89 // System.out.println("Skipping creation of " + sectName + " section, no data\n"); 90 } 91 92 MachOSection sect = new MachOSection(sectName, 93 segName, 94 c.getByteArray(), 95 scnFlags, 96 c.hasRelocations(), 97 segmentSize); 98 // Add this section to our list 99 sections.add(sect); 100 101 // Record the section Id (0 relative) 102 c.setSectionId(sections.size() - 1); 103 104 // TODO: Clear out code section data to allow for GC 105 // c.clear(); 106 } 107 108 private void createCodeSection(ArrayList<MachOSection> sections, CodeContainer c) { 109 createByteSection(sections, c, /* c.getContainerName() */ "__text", "__TEXT", 110 section_64.S_ATTR_PURE_INSTRUCTIONS | 111 section_64.S_ATTR_SOME_INSTRUCTIONS); 112 } 113 114 private void createReadOnlySection(ArrayList<MachOSection> sections, ReadOnlyDataContainer c) { 115 createByteSection(sections, c, c.getContainerName(), "__TEXT", 116 section_64.S_ATTR_SOME_INSTRUCTIONS); 117 } 118 119 private void createReadWriteSection(ArrayList<MachOSection> sections, ByteContainer c) { 120 createByteSection(sections, c, c.getContainerName(), "__DATA", section_64.S_REGULAR); 121 } 122 123 /** 124 * Create an MachO relocatable object 125 * 126 * @param relocationTable 127 * @param symbols 128 * @throws IOException throws {@code IOException} as a result of file system access failures. 129 */ 130 public void createMachORelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException { 131 // Allocate MachO Header 132 // with 4 load commands 133 // LC_SEGMENT_64 134 // LC_VERSION_MIN_MACOSX 135 // LC_SYMTAB 136 // LC_DYSYMTAB 137 138 MachOHeader mh = new MachOHeader(); 139 140 ArrayList<MachOSection> sections = new ArrayList<>(); 141 142 // Create Sections contained in the main Segment LC_SEGMENT_64 143 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 createReadOnlySection(sections, binContainer.getMethodMetadataContainer()); 150 createReadOnlySection(sections, binContainer.getStubsOffsetsContainer()); 151 createReadOnlySection(sections, binContainer.getHeaderContainer().getContainer()); 152 createReadOnlySection(sections, binContainer.getCodeSegmentsContainer()); 153 createReadOnlySection(sections, binContainer.getConstantDataContainer()); 154 createReadOnlySection(sections, binContainer.getConfigContainer()); 155 createReadWriteSection(sections, binContainer.getKlassesGotContainer()); 156 createReadWriteSection(sections, binContainer.getCountersGotContainer()); 157 createReadWriteSection(sections, binContainer.getMetadataGotContainer()); 158 createReadWriteSection(sections, binContainer.getMethodStateContainer()); 159 createReadWriteSection(sections, binContainer.getOopGotContainer()); 160 createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); 161 162 // Update the Header sizeofcmds size. 163 // This doesn't include the Header struct size 164 mh.setCmdSizes(4, segment_command_64.totalsize + 165 (section_64.totalsize * sections.size()) + 166 version_min_command.totalsize + 167 symtab_command.totalsize + 168 dysymtab_command.totalsize); 169 170 // Initialize file offset for data past commands 171 int file_offset = mach_header_64.totalsize + mh.getCmdSize(); 172 // and round it up 173 file_offset = (file_offset + (sections.get(0).getAlign() - 1)) & ~((sections.get(0).getAlign() - 1)); 174 long address = 0; 175 int segment_offset = file_offset; 176 177 for (int i = 0; i < sections.size(); i++) { 178 MachOSection sect = sections.get(i); 179 file_offset = (file_offset + (sect.getAlign() - 1)) & ~((sect.getAlign() - 1)); 180 address = (address + (sect.getAlign() - 1)) & ~((sect.getAlign() - 1)); 181 sect.setOffset(file_offset); 182 sect.setAddr(address); 183 file_offset += sect.getSize(); 184 address += sect.getSize(); 185 } 186 187 // File size for Segment data 188 int segment_size = file_offset - segment_offset; 189 190 // Create the LC_SEGMENT_64 Segment which contains the MachOSections 191 MachOSegment seg = new MachOSegment(segment_command_64.totalsize + 192 (section_64.totalsize * sections.size()), 193 segment_offset, 194 segment_size, 195 sections.size()); 196 197 MachOVersion vers = new MachOVersion(); 198 199 // Get symbol data from BinaryContainer object's symbol tables 200 MachOSymtab symtab = createMachOSymbolTables(sections, symbols); 201 202 // Create LC_DYSYMTAB command 203 MachODySymtab dysymtab = new MachODySymtab(symtab.getNumLocalSyms(), 204 symtab.getNumGlobalSyms(), 205 symtab.getNumUndefSyms()); 206 207 // Create the Relocation Tables 208 MachORelocTable machORelocs = createMachORelocTable(sections, relocationTable, symtab); 209 // Calculate file offset for relocation data 210 file_offset = (file_offset + (MachORelocTable.getAlign() - 1)) & ~((MachORelocTable.getAlign() - 1)); 211 212 // Update relocation sizing information in each section 213 for (int i = 0; i < sections.size(); i++) { 214 MachOSection sect = sections.get(i); 215 if (sect.hasRelocations()) { 216 int nreloc = machORelocs.getNumRelocs(i); 217 sect.setReloff(file_offset); 218 sect.setRelcount(nreloc); 219 file_offset += (nreloc * reloc_info.totalsize); 220 } 221 } 222 223 // Calculate and set file offset for symbol table data 224 file_offset = (file_offset + (MachOSymtab.getAlign() - 1)) & ~((MachOSymtab.getAlign() - 1)); 225 symtab.setOffset(file_offset); 226 227 // Write Out Header 228 machoContainer.writeBytes(mh.getArray()); 229 // Write out first Segment 230 machoContainer.writeBytes(seg.getArray()); 231 // Write out sections within first Segment 232 for (int i = 0; i < sections.size(); i++) { 233 MachOSection sect = sections.get(i); 234 machoContainer.writeBytes(sect.getArray()); 235 } 236 237 // Write out LC_VERSION_MIN_MACOSX command 238 machoContainer.writeBytes(vers.getArray()); 239 240 // Write out LC_SYMTAB command 241 symtab.calcSizes(); 242 machoContainer.writeBytes(symtab.getCmdArray()); 243 244 // Write out LC_DYSYMTAB command 245 machoContainer.writeBytes(dysymtab.getArray()); 246 247 // Write out data associated with each Section 248 for (int i = 0; i < sections.size(); i++) { 249 MachOSection sect = sections.get(i); 250 machoContainer.writeBytes(sect.getDataArray(), sect.getAlign()); 251 } 252 253 // Write out the relocation tables for all sections 254 for (int i = 0; i < sections.size(); i++) { 255 if (machORelocs.getNumRelocs(i) > 0) { 256 machoContainer.writeBytes(machORelocs.getRelocData(i), MachORelocTable.getAlign()); 257 } 258 } 259 260 // Write out data associated with LC_SYMTAB 261 machoContainer.writeBytes(symtab.getDataArray(), MachOSymtab.getAlign()); 262 263 machoContainer.close(); 264 } 265 266 /** 267 * Construct MachO symbol data from BinaryContainer object's symbol tables. Both dynamic MachO 268 * symbol table and MachO symbol table are created from BinaryContainer's symbol info. 269 * 270 * @param sections 271 * @param symbols 272 */ 273 private static MachOSymtab createMachOSymbolTables(ArrayList<MachOSection> sections, 274 Collection<Symbol> symbols) { 275 MachOSymtab symtab = new MachOSymtab(); 276 // First, create the initial null symbol. This is a local symbol. 277 symtab.addSymbolEntry("", (byte) nlist_64.N_UNDF, (byte) 0, 0); 278 279 // Now create MachO symbol entries for all symbols. 280 for (Symbol symbol : symbols) { 281 int sectionId = symbol.getSection().getSectionId(); 282 283 // Symbol offsets are relative to the section memory addr 284 long sectionAddr = sections.get(sectionId).getAddr(); 285 286 MachOSymbol machoSymbol = symtab.addSymbolEntry(symbol.getName(), 287 getMachOTypeOf(symbol), 288 (byte) sectionId, 289 symbol.getOffset() + sectionAddr); 290 symbol.setNativeSymbol(machoSymbol); 291 } 292 293 // Now that all symbols are enterred, update the 294 // symbol indexes. This is necessary since they will 295 // be reordered based on local, global and undefined. 296 symtab.updateIndexes(); 297 298 return (symtab); 299 } 300 301 private static byte getMachOTypeOf(Symbol sym) { 302 Kind kind = sym.getKind(); 303 byte type = nlist_64.N_UNDF; 304 305 // Global or Local 306 if (sym.getBinding() == Symbol.Binding.GLOBAL) { 307 type = nlist_64.N_EXT; 308 } 309 // If Function or Data, add section type 310 if (kind == Symbol.Kind.NATIVE_FUNCTION || 311 kind == Symbol.Kind.JAVA_FUNCTION || 312 kind == Symbol.Kind.OBJECT) { 313 type |= (nlist_64.N_SECT); 314 } 315 316 return (type); 317 } 318 319 /** 320 * Construct a MachO relocation table from BinaryContainer object's relocation tables. 321 * 322 * @param sections 323 * @param relocationTable 324 * @param symtab 325 */ 326 private MachORelocTable createMachORelocTable(ArrayList<MachOSection> sections, 327 Map<Symbol, List<Relocation>> relocationTable, 328 MachOSymtab symtab) { 329 330 MachORelocTable machORelocTable = new MachORelocTable(sections.size()); 331 /* 332 * For each of the symbols with associated relocation records, create a MachO relocation entry. 333 */ 334 for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) { 335 List<Relocation> relocs = entry.getValue(); 336 Symbol symbol = entry.getKey(); 337 338 for (Relocation reloc : relocs) { 339 createRelocation(symbol, reloc, machORelocTable); 340 } 341 } 342 343 for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) { 344 createRelocation(entry.getKey(), entry.getValue(), machORelocTable); 345 } 346 347 return (machORelocTable); 348 } 349 350 private static void createRelocation(Symbol symbol, Relocation reloc, MachORelocTable machORelocTable) { 351 RelocType relocType = reloc.getType(); 352 353 int machORelocType = getMachORelocationType(relocType); 354 MachOSymbol sym = (MachOSymbol) symbol.getNativeSymbol(); 355 int symno = sym.getIndex(); 356 int sectindex = reloc.getSection().getSectionId(); 357 int offset = reloc.getOffset(); 358 int pcrel = 0; 359 int length = 0; 360 int isextern = 1; 361 362 switch (relocType) { 363 case JAVA_CALL_DIRECT: 364 case STUB_CALL_DIRECT: 365 case FOREIGN_CALL_INDIRECT_GOT: { 366 // Create relocation entry 367 int addend = -4; // Size in bytes of the patch location 368 // Relocation should be applied at the location after call operand 369 offset = offset + reloc.getSize() + addend; 370 pcrel = 1; 371 length = 2; 372 break; 373 } 374 case JAVA_CALL_INDIRECT: { 375 // Do nothing. 376 return; 377 } 378 case METASPACE_GOT_REFERENCE: 379 case EXTERNAL_PLT_TO_GOT: { 380 int addend = -4; // Size of 32-bit address of the GOT 381 /* 382 * Relocation should be applied before the test instruction to the move instruction. 383 * reloc.getOffset() points to the test instruction after the instruction that loads the address of 384 * polling page. So set the offset appropriately. 385 */ 386 offset = offset + addend; 387 pcrel = 1; 388 length = 2; 389 break; 390 } 391 case EXTERNAL_GOT_TO_PLT: { 392 // this is load time relocations 393 pcrel = 0; 394 length = 3; 395 break; 396 } 397 default: 398 throw new InternalError("Unhandled relocation type: " + relocType); 399 } 400 machORelocTable.createRelocationEntry(sectindex, offset, symno, 401 pcrel, length, isextern, 402 machORelocType); 403 } 404 405 private static int getMachORelocationType(RelocType relocType) { 406 int machORelocType = 0; 407 switch (MachOTargetInfo.getMachOArch()) { 408 case mach_header_64.CPU_TYPE_X86_64: 409 // Return X86_64_RELOC_* entries based on relocType 410 if (relocType == RelocType.JAVA_CALL_DIRECT || 411 relocType == RelocType.FOREIGN_CALL_INDIRECT_GOT) { 412 machORelocType = reloc_info.X86_64_RELOC_BRANCH; 413 } else if (relocType == RelocType.STUB_CALL_DIRECT) { 414 machORelocType = reloc_info.X86_64_RELOC_BRANCH; 415 } else if (relocType == RelocType.JAVA_CALL_INDIRECT) { 416 machORelocType = reloc_info.X86_64_RELOC_NONE; 417 } else if (relocType == RelocType.METASPACE_GOT_REFERENCE || 418 relocType == RelocType.EXTERNAL_PLT_TO_GOT) { 419 machORelocType = reloc_info.X86_64_RELOC_BRANCH; 420 } else if (relocType == RelocType.EXTERNAL_GOT_TO_PLT) { 421 machORelocType = reloc_info.X86_64_RELOC_UNSIGNED; 422 } else { 423 assert false : "Unhandled relocation type: " + relocType; 424 } 425 break; 426 default: 427 System.out.println("Relocation Type mapping: Unhandled architecture"); 428 } 429 return machORelocType; 430 } 431 } |