src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java
Index Unified diffs Context diffs Sdiffs Frames Patch New Old Previous File Next File hotspot Sdiff src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho

src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java

Print this page




  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 }
src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/macho/JMachORelocObject.java
Index Unified diffs Context diffs Sdiffs Frames Patch New Old Previous File Next File