1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.tools.jaotc.binformat.elf; 25 26 import java.io.IOException; 27 import java.util.ArrayList; 28 import java.util.Collection; 29 import java.util.List; 30 import java.util.Map; 31 32 import jdk.tools.jaotc.binformat.BinaryContainer; 33 import jdk.tools.jaotc.binformat.ByteContainer; 34 import jdk.tools.jaotc.binformat.CodeContainer; 35 import jdk.tools.jaotc.binformat.ReadOnlyDataContainer; 36 import jdk.tools.jaotc.binformat.Relocation; 37 import jdk.tools.jaotc.binformat.Relocation.RelocType; 38 import jdk.tools.jaotc.binformat.Symbol; 39 import jdk.tools.jaotc.binformat.Symbol.Binding; 40 import jdk.tools.jaotc.binformat.Symbol.Kind; 41 42 import jdk.tools.jaotc.binformat.elf.ElfSymbol; 43 import jdk.tools.jaotc.binformat.elf.ElfTargetInfo; 44 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Ehdr; 45 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Shdr; 46 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Sym; 47 import jdk.tools.jaotc.binformat.elf.Elf.Elf64_Rela; 48 49 public abstract class JELFRelocObject { 50 51 private final BinaryContainer binContainer; 52 53 private final ElfContainer elfContainer; 54 55 private final int segmentSize; 56 57 protected JELFRelocObject(BinaryContainer binContainer, String outputFileName) { 58 this.binContainer = binContainer; 59 this.elfContainer = new ElfContainer(outputFileName); 60 this.segmentSize = binContainer.getCodeSegmentSize(); 61 } 62 63 public static JELFRelocObject newInstance(BinaryContainer binContainer, String outputFileName) { 64 String archStr = System.getProperty("os.arch").toLowerCase(); 65 if (archStr.equals("amd64") || archStr.equals("x86_64")) { 66 return new AMD64JELFRelocObject(binContainer, outputFileName); 67 } else if (archStr.equals("aarch64")) { 68 return new AArch64JELFRelocObject(binContainer, outputFileName); 69 } 70 throw new InternalError("Unsupported platform: " + archStr); 71 } 72 73 private static ElfSection createByteSection(ArrayList<ElfSection> sections, 74 String sectName, 75 byte[] scnData, 76 boolean hasRelocs, 77 int align, 78 int scnFlags, 79 int scnType) { 80 81 ElfSection sect = new ElfSection(sectName, scnData, scnFlags, scnType, 82 hasRelocs, align, sections.size()); 83 // Add this section to our list 84 sections.add(sect); 85 86 return (sect); 87 } 88 89 private void createByteSection(ArrayList<ElfSection> sections, 90 ByteContainer c, int scnFlags) { 91 ElfSection sect; 92 boolean hasRelocs = c.hasRelocations(); 93 byte[] scnData = c.getByteArray(); 94 95 int scnType = Elf64_Shdr.SHT_PROGBITS; 96 boolean zeros = !hasRelocs; 97 if (zeros) { 98 for (byte b : scnData) { 99 if (b != 0) { 100 zeros = false; 101 break; 102 } 103 } 104 if (zeros) { 105 scnType = Elf64_Shdr.SHT_NOBITS; 106 } 107 } 108 109 sect = createByteSection(sections, c.getContainerName(), 110 scnData, hasRelocs, segmentSize, 111 scnFlags, scnType); 112 c.setSectionId(sect.getSectionId()); 113 } 114 115 private void createCodeSection(ArrayList<ElfSection> sections, CodeContainer c) { 116 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_EXECINSTR); 117 } 118 119 private void createReadOnlySection(ArrayList<ElfSection> sections, ReadOnlyDataContainer c) { 120 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC); 121 } 122 123 private void createReadWriteSection(ArrayList<ElfSection> sections, ByteContainer c) { 124 createByteSection(sections, c, Elf64_Shdr.SHF_ALLOC | Elf64_Shdr.SHF_WRITE); 125 } 126 127 /** 128 * Create an ELF relocatable object 129 * 130 * @param relocationTable 131 * @param symbols 132 * @throws IOException throws {@code IOException} as a result of file system access failures. 133 */ 134 public void createELFRelocObject(Map<Symbol, List<Relocation>> relocationTable, Collection<Symbol> symbols) throws IOException { 135 // Allocate ELF Header 136 ElfHeader eh = new ElfHeader(); 137 138 ArrayList<ElfSection> sections = new ArrayList<>(); 139 140 // Create the null section 141 createByteSection(sections, null, null, false, 1, 0, 0); 142 143 // Create text section 144 createCodeSection(sections, binContainer.getCodeContainer()); 145 createReadOnlySection(sections, binContainer.getMetaspaceNamesContainer()); 146 createReadOnlySection(sections, binContainer.getKlassesOffsetsContainer()); 147 createReadOnlySection(sections, binContainer.getMethodsOffsetsContainer()); 148 createReadOnlySection(sections, binContainer.getKlassesDependenciesContainer()); 149 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.getOopGotContainer()); 159 createReadWriteSection(sections, binContainer.getMethodStateContainer()); 160 createReadWriteSection(sections, binContainer.getExtLinkageGOTContainer()); 161 162 // Get ELF symbol data from BinaryContainer object's symbol tables 163 ElfSymtab symtab = createELFSymbolTables(symbols); 164 165 // Create string table section and symbol table sections in 166 // that order since symtab section needs to set the index of 167 // strtab in sh_link field 168 ElfSection strTabSection = createByteSection(sections, ".strtab", 169 symtab.getStrtabArray(), 170 false, 1, 0, 171 Elf64_Shdr.SHT_STRTAB); 172 173 // Now create .symtab section with the symtab data constructed. 174 // On Linux, sh_link of symtab contains the index of string table 175 // its symbols reference and sh_info contains the index of first 176 // non-local symbol 177 ElfSection symTabSection = createByteSection(sections, ".symtab", 178 symtab.getSymtabArray(), 179 false, 8, 0, 180 Elf64_Shdr.SHT_SYMTAB); 181 symTabSection.setLink(strTabSection.getSectionId()); 182 symTabSection.setInfo(symtab.getNumLocalSyms()); 183 184 ElfRelocTable elfRelocTable = createElfRelocTable(sections, relocationTable); 185 186 createElfRelocSections(sections, elfRelocTable, symTabSection.getSectionId()); 187 188 // Now, finally, after creating all sections, create shstrtab section 189 ElfSection shStrTabSection = createByteSection(sections, ".shstrtab", 190 null, false, 1, 0, 191 Elf64_Shdr.SHT_STRTAB); 192 eh.setSectionStrNdx(shStrTabSection.getSectionId()); 193 194 // Update all section offsets and the Elf header section offset 195 // Write the Header followed by the contents of each section 196 // and then the section structures (section table). 197 int file_offset = Elf64_Ehdr.totalsize; 198 199 // and round it up 200 file_offset = (file_offset + (sections.get(1).getDataAlign() - 1)) & 201 ~((sections.get(1).getDataAlign() - 1)); 202 203 // Calc file offsets for section data skipping null section 204 for (int i = 1; i < sections.size(); i++) { 205 ElfSection sect = sections.get(i); 206 file_offset = (file_offset + (sect.getDataAlign() - 1)) & 207 ~((sect.getDataAlign() - 1)); 208 sect.setOffset(file_offset); 209 file_offset += sect.getSize(); 210 } 211 212 // Align the section table 213 file_offset = (file_offset + (ElfSection.getShdrAlign() - 1)) & 214 ~((ElfSection.getShdrAlign() - 1)); 215 216 // Update the Elf Header with the offset of the first Elf64_Shdr 217 // and the number of sections. 218 eh.setSectionOff(file_offset); 219 eh.setSectionNum(sections.size()); 220 221 // Write out the Header 222 elfContainer.writeBytes(eh.getArray()); 223 224 // Write out each section contents skipping null section 225 for (int i = 1; i < sections.size(); i++) { 226 ElfSection sect = sections.get(i); 227 elfContainer.writeBytes(sect.getDataArray(), sect.getDataAlign()); 228 } 229 230 // Write out the section table 231 for (int i = 0; i < sections.size(); i++) { 232 ElfSection sect = sections.get(i); 233 elfContainer.writeBytes(sect.getArray(), ElfSection.getShdrAlign()); 234 } 235 236 elfContainer.close(); 237 } 238 239 /** 240 * Construct ELF symbol data from BinaryContainer object's symbol tables. Both dynamic ELF symbol 241 * table and ELF symbol table are created from BinaryContainer's symbol info. 242 * 243 * @param symbols 244 */ 245 private static ElfSymtab createELFSymbolTables(Collection<Symbol> symbols) { 246 ElfSymtab symtab = new ElfSymtab(); 247 248 // First, create the initial null symbol. This is a local symbol. 249 symtab.addSymbolEntry("", (byte) 0, (byte) 0, Elf64_Shdr.SHN_UNDEF, 0, 0); 250 251 // Now create ELF symbol entries for all symbols. 252 for (Symbol symbol : symbols) { 253 // Get the index of section this symbol is defined in. 254 int secHdrIndex = symbol.getSection().getSectionId(); 255 ElfSymbol elfSymbol = symtab.addSymbolEntry(symbol.getName(), getELFTypeOf(symbol), getELFBindOf(symbol), (byte) secHdrIndex, symbol.getOffset(), symbol.getSize()); 256 symbol.setNativeSymbol(elfSymbol); 257 } 258 return (symtab); 259 } 260 261 private static byte getELFTypeOf(Symbol sym) { 262 Kind kind = sym.getKind(); 263 if (kind == Symbol.Kind.NATIVE_FUNCTION || kind == Symbol.Kind.JAVA_FUNCTION) { 264 return Elf64_Sym.STT_FUNC; 265 } else if (kind == Symbol.Kind.OBJECT) { 266 return Elf64_Sym.STT_OBJECT; 267 } 268 return Elf64_Sym.STT_NOTYPE; 269 } 270 271 private static byte getELFBindOf(Symbol sym) { 272 Binding binding = sym.getBinding(); 273 if (binding == Symbol.Binding.GLOBAL) { 274 return Elf64_Sym.STB_GLOBAL; 275 } 276 return Elf64_Sym.STB_LOCAL; 277 } 278 279 /** 280 * Construct a Elf relocation table from BinaryContainer object's relocation tables. 281 * 282 * @param sections 283 * @param relocationTable 284 */ 285 private ElfRelocTable createElfRelocTable(ArrayList<ElfSection> sections, 286 Map<Symbol, List<Relocation>> relocationTable) { 287 288 ElfRelocTable elfRelocTable = new ElfRelocTable(sections.size()); 289 /* 290 * For each of the symbols with associated relocation records, create a Elf relocation entry. 291 */ 292 for (Map.Entry<Symbol, List<Relocation>> entry : relocationTable.entrySet()) { 293 List<Relocation> relocs = entry.getValue(); 294 Symbol symbol = entry.getKey(); 295 296 for (Relocation reloc : relocs) { 297 createRelocation(symbol, reloc, elfRelocTable); 298 } 299 } 300 301 for (Map.Entry<Symbol, Relocation> entry : binContainer.getUniqueRelocationTable().entrySet()) { 302 createRelocation(entry.getKey(), entry.getValue(), elfRelocTable); 303 } 304 305 return (elfRelocTable); 306 } 307 308 private static void createElfRelocSections(ArrayList<ElfSection> sections, 309 ElfRelocTable elfRelocTable, 310 int symtabsectidx) { 311 312 // Grab count before we create new sections 313 int count = sections.size(); 314 315 for (int i = 0; i < count; i++) { 316 if (elfRelocTable.getNumRelocs(i) > 0) { 317 ElfSection sect = sections.get(i); 318 String relname = ".rela" + sect.getName(); 319 ElfSection relocSection = createByteSection(sections, relname, 320 elfRelocTable.getRelocData(i), 321 false, 8, 0, Elf64_Shdr.SHT_RELA); 322 relocSection.setLink(symtabsectidx); 323 relocSection.setInfo(sect.getSectionId()); 324 } 325 } 326 } 327 328 abstract void createRelocation(Symbol symbol, Relocation reloc, ElfRelocTable elfRelocTable); 329 330 }