/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.linker; import java.io.IOException; import org.jnode.assembler.Label; import org.jnode.assembler.NativeStream; import org.jnode.assembler.UnresolvedObjectRefException; import org.jnode.assembler.x86.X86Assembler; import org.jnode.build.BuildException; /** * Build the boot image from an assembler compiled bootstrap (in ELF format) * combined with the precompiled Java classes. */ public class ElfLinker { private X86Assembler os; private int start; private int baseAddr; public ElfLinker(X86Assembler os) { this.os = os; baseAddr = (int) os.getBaseAddr(); } /** * Load an ELF object file with a given name and link it into the native * stream. */ public void loadElfObject(String name) throws BuildException { Elf elf; try { elf = Elf.newFromFile(name); loadElfObject(elf); } catch (IOException ex) { throw new BuildException(ex); } } /** * Load an ELF object file with a given name and link it into the native * stream. */ public void loadElfObject(Elf elf) throws BuildException { if (!elf.isRel()) { throw new BuildException("Elf object is not relocatable"); } final Section text = elf.getSectionByName(".text"); if (text == null) { throw new BuildException(".text section not found"); } // Write the code start = os.getLength(); final byte[] tdata = text.getBody(); os.write(tdata, 0, tdata.length); // Add all resolved symbols final int symCnt = elf.getNoSymbols(); for (int i = 1; i < symCnt; i++) { final Symbol sym = elf.getSymbol(i); final Section sec = sym.getSection(); if (sec == text) { // System.out.println(sym); NativeStream.ObjectRef ref = os.getObjectRef(new Label(sym.getName())); ref.setPublic(); if (!sym.isUndef()) { // System.out.println("Defined symbol at " + sym.getValue() // + " [" + sym.getName() + "]"); ref.setOffset((int) sym.getValue() + start); } else { System.out.println("Undefined symbol: " + sym.getName()); } } else if ((sec != null) && !sym.isUndef()) { System.out.println("Symbol '" + sym.getName() + "' refers to unknown section '" + sec.getName() + "'"); } } // Add all relocation items Section rels = elf.getSectionByName(".rel.text"); if (rels == null) { rels = elf.getSectionByName(".rela.text"); } if (rels != null) { final int relocCnt = rels.getNoRelocs(); for (int i = 0; i < relocCnt; i++) { try { final Reloc r = rels.getReloc(i); final String symName = r.getSymbol().getName(); final boolean hasSymName = (symName.length() > 0); final boolean hasAddEnd = r.hasAddEnd(); final long addr = r.getAddress() + start; final long addend = r.getAddEnd(); final Reloc.Type relocType = r.getRelocType(); if ((relocType == Reloc.R_386_32) && !hasAddEnd) { resolve_R386_32(addr, symName, hasSymName); } else if ((relocType == Reloc.R_386_PC32) && !hasAddEnd) { resolve_R386_PC32(addr, symName, hasSymName); } else if ((relocType == Reloc.R_X86_64_32) && hasAddEnd) { resolve_R_X86_64_32(addr, addend, symName, hasSymName); } else if ((relocType == Reloc.R_X86_64_64) && hasAddEnd) { resolve_R_X86_64_64(addr, addend, symName, hasSymName); } else { throw new BuildException("Unknown relocation type " + relocType); } } catch (UnresolvedObjectRefException ex) { throw new BuildException(ex); } } } } /** * Resolve an absolute 32-bit address. * * @param addr * @param symName * @param hasSymName * @throws UnresolvedObjectRefException */ private void resolve_R386_32(long addr, String symName, boolean hasSymName) throws UnresolvedObjectRefException { if (!hasSymName) { os.set32((int) addr, os.get32((int) addr) + start + baseAddr); } else { final NativeStream.ObjectRef ref = os.getObjectRef(new Label(symName)); if (ref.isResolved()) { os.set32((int) addr, ref.getOffset() + baseAddr); } else { os.set32((int) addr, -baseAddr); ref.addUnresolvedLink((int) addr, 4); } } } /** * Resolve an pc-relative 32-bit address. * * @param addr * @param symName * @param hasSymName * @throws UnresolvedObjectRefException */ private void resolve_R386_PC32(long addr, String symName, boolean hasSymName) throws UnresolvedObjectRefException { final NativeStream.ObjectRef ref = os.getObjectRef(new Label(symName)); if (ref.isResolved()) { os.set32((int) addr, (int) (ref.getOffset() - (addr + 4))); } else { ref.addUnresolvedLink((int) addr, 4); } } /** * Resolve a direct 32 bit zero extended address. * * @param addr * @param symName * @param hasSymName * @throws UnresolvedObjectRefException */ private void resolve_R_X86_64_32(long addr, long addend, String symName, boolean hasSymName) throws UnresolvedObjectRefException { if (!hasSymName) { os.set32((int) addr, (int) (addend + start + baseAddr)); } else { final NativeStream.ObjectRef ref = os.getObjectRef(new Label(symName)); if (ref.isResolved()) { os.set32((int) addr, (int) (ref.getOffset() + baseAddr + addend)); } else { os.set32((int) addr, (int) -(baseAddr + addend)); ref.addUnresolvedLink((int) addr, 4); } } } /** * Resolve a direct 64 bit address. * * @param addr * @param symName * @param hasSymName * @throws UnresolvedObjectRefException */ private void resolve_R_X86_64_64(long addr, long addend, String symName, boolean hasSymName) throws UnresolvedObjectRefException { if (!hasSymName) { os.set64((int) addr, addend + start + baseAddr); } else { final NativeStream.ObjectRef ref = os.getObjectRef(new Label(symName)); if (ref.isResolved()) { os.set64((int) addr, ref.getOffset() + baseAddr + addend); } else { os.set64((int) addr, -(baseAddr + addend)); ref.addUnresolvedLink((int) addr, 8); } } } }