/* * $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; // // ---- Section Header --- // typedef struct // { // Elf32_Word sh_name; /* Section name (string tbl index) */ // Elf32_Word sh_type; /* Section type */ // Elf32_Word sh_flags; /* Section flags */ // Elf32_Addr sh_addr; /* Section virtual addr at execution */ // Elf32_Off sh_offset; /* Section file offset */ // Elf32_Word sh_size; /* Section size in bytes */ // Elf32_Word sh_link; /* Link to another section */ // Elf32_Word sh_info; /* Additional section information */ // Elf32_Word sh_addralign; /* Section alignment */ // Elf32_Word sh_entsize; /* Entry size if section holds table */ // } Elf32_Shdr; // import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; import java.util.Vector; public class Section { public static final int SHT_NULL = 0; public static final int SHT_PROGBITS = 1; public static final int SHT_SYMTAB = 2; public static final int SHT_STRTAB = 3; public static final int SHT_RELA = 4; public static final int SHT_HASH = 5; public static final int SHT_DYNAMIC = 6; public static final int SHT_NOTE = 7; public static final int SHT_NOBITS = 8; public static final int SHT_REL = 9; public static final int SHT_SHLIB = 10; public static final int SHT_DYNSYM = 11; public static final int SHF_WRITE = 0x1; public static final int SHF_ALLOC = 0x2; public static final int SHF_EXECINSTR = 0x4; public static final int SHF_MASKPROC = 0xf0000000; static String typename[] = {"NULL", "PROGBITS", "SYMTAB", "STRTAB", "RELA", "HASH", "DYNAMIC", "NOTE", "NOBITS", "REL", "SHLIB", "DYNSYM", "NUM"}; int sh_name; int sh_type; long sh_flags; long sh_addr; long sh_offset; long sh_size; int sh_link; int sh_info; long sh_addralign; long sh_entsize; final Elf elf; byte[] m_body; Vector<Symbol> m_symtab; // char[] m_strtab; Vector<Reloc> m_reltab; private StrTab strTab; private Section(Elf elf, int type, String name, int flags) { this.elf = elf; this.sh_type = type; this.sh_flags = flags; m_symtab = new Vector<Symbol>(); m_reltab = new Vector<Reloc>(); strTab = new StrTab(); if (name != null) { Section shstr = elf.getSHStrSection(); if (shstr == null) { shstr = this; } sh_name = shstr.addString(name); sh_addralign = 1; } } public static Section newNullInstance(Elf elf) { return new Section(elf, 0, null, 0); } public static Section newInstance(Elf elf, RandomAccessFile in) throws IOException { Section s = new Section(elf, 0, null, 0); s.load(in); return s; } public static Section newRelTabSection(Elf elf, Section symtabSection, Section contentSection) { Section s = new Section(elf, SHT_REL, ".rel" + contentSection.getName(), SHF_ALLOC); s.sh_entsize = 0x08; s.sh_link = elf.getSectionIndex(symtabSection); s.sh_info = elf.getSectionIndex(contentSection); return s; } public static Section newStrTabSection(Elf elf) { return new Section(elf, SHT_STRTAB, (elf.getSHStrSection() == null) ? ".shstrtab" : ".strtab", SHF_ALLOC); } public static Section newSymTabSection(Elf elf) { Section s = new Section(elf, SHT_SYMTAB, ".symtab", SHF_ALLOC); s.m_symtab.addElement(new Symbol(elf, null, 0, null)); // First entry must be NULL s.sh_entsize = 0x10; s.sh_link = elf.getSectionIndex(elf.getSectionByName(".strtab")); return s; } public static Section newTextSection(Elf elf) { return new Section(elf, SHT_PROGBITS, ".text", SHF_ALLOC | SHF_EXECINSTR); } public static Section newDataSection(Elf elf) { return new Section(elf, SHT_PROGBITS, ".data", SHF_WRITE | SHF_ALLOC); } public static Section newBssSection(Elf elf) { return new Section(elf, SHT_NOBITS, ".bss", SHF_WRITE | SHF_ALLOC); } /** * Gets the name of this section. * * @return the name of this section */ public String getName() { return elf.getSHString(sh_name); } public int getType() { return sh_type; } public String getTypeName() { return typename[sh_type]; } public long getFlags() { return sh_flags; } public void setFlags(long v) { sh_flags = v; } public long getAddr() { return sh_addr; } public long getOffset() { return sh_offset; } public void setOffset(long ofs) { sh_offset = ofs; } public long getSize() { return sh_size; } public int getLink() { return sh_link; } public void setLink(int v) { sh_link = v; } public long getAlign() { return sh_addralign; } public void setAlign(long v) { sh_addralign = v; } public long getEntrySize() { return sh_entsize; } public byte[] getBody() { return m_body; } public void setBody(byte[] v) { setBody(v, 0, v.length); } public void setBody(byte[] v, int start, int length) { m_body = new byte[length]; System.arraycopy(v, start, m_body, 0, length); sh_size = m_body.length; } // public char[] getStrTab() { return m_strtab; } public boolean isBss() { return (sh_type == SHT_NOBITS); } public boolean isSymTab() { return (sh_type == SHT_SYMTAB); } public boolean isStrTab() { return (sh_type == SHT_STRTAB); } public boolean isRelTab() { return (sh_type == SHT_REL); } public boolean isRelaTab() { return (sh_type == SHT_RELA); } public int getNoRelocs() { if (!(isRelTab() || isRelaTab())) throw new RuntimeException("Only valid to reloc table sections"); return m_reltab.size(); } public Reloc getReloc(int index) { if (!(isRelTab() || isRelaTab())) throw new RuntimeException("Only valid to reloc table sections"); return m_reltab.elementAt(index); } public void addAbsReloc(Symbol symbol, int address) { if (!isRelTab()) { throw new RuntimeException("Only valid to reloc table sections"); } m_reltab.addElement(Reloc.newAbsInstance(elf, symbol, address)); } public void addPcRelReloc(Symbol symbol, int address) { if (!isRelTab()) { throw new RuntimeException("Only valid to reloc table sections"); } m_reltab.addElement(Reloc.newPcRelInstance(elf, symbol, address)); } public int getNoSymbols() { if (!isSymTab()) throw new RuntimeException("Only valid to symbol table sections"); return m_symtab.size(); } public Symbol getSymbol(int index) { if (!isSymTab()) { throw new RuntimeException("Only valid to symbol table sections"); } return m_symtab.elementAt(index); } public Symbol getSymbolByAddress(int address) { //todo investigate: if statement buggy? if (!isSymTab()) throw new RuntimeException("Only valid to symbol table sections"); int i; for (i = 1; i < getNoSymbols(); i++) { Symbol s = getSymbol(i); if (address == s.getValue()) ; return s; } return null; } public void addSymbol(Symbol s) { m_symtab.addElement(s); } public int getIndexOfSymbol(Symbol symbol) { return m_symtab.indexOf(symbol); } public String getString(int addr) { return strTab.getString(addr); } /** * Add a string and return its index. * * @param v */ public synchronized int addString(String v) { if (!isStrTab()) { throw new RuntimeException("Only valid for StrTab sections"); } return strTab.addString(v); } /** * Return the index of a given string, or -1 if not found. */ public synchronized int findString(String v) { return strTab.findString(v); } public void print() { System.out.println(" ----- Section Header -----"); System.out.println(" sh_name : " + Integer.toString(sh_name, 16) + "(" + getName() + ")"); System.out.println(" sh_type : " + Integer.toString(sh_type, 16) + "(" + typename[sh_type] + ")"); System.out.println(" sh_flags : " + Long.toString(sh_flags, 16)); System.out.println(" sh_addr : " + Long.toString(sh_addr, 16)); System.out.println(" sh_offset : " + Long.toString(sh_offset, 16)); System.out.println(" sh_size : " + Long.toString(sh_size, 16)); System.out.println(" sh_link : " + Integer.toString(sh_link, 16)); System.out.println(" sh_info : " + Integer.toString(sh_info, 16)); System.out.println(" sh_addralign : " + Long.toString(sh_addralign, 16)); System.out.println(" sh_entsize : " + Long.toString(sh_entsize, 16)); } protected long get_brk() { return (sh_addr + sh_size); } private void load(RandomAccessFile in) throws IOException { sh_name = LoadUtil.little32(in); sh_type = LoadUtil.little32(in); sh_flags = LoadUtil.loadXword(in, elf.e_ident); sh_addr = LoadUtil.loadAddr(in, elf.e_ident); sh_offset = LoadUtil.loadOff(in, elf.e_ident); sh_size = LoadUtil.loadXword(in, elf.e_ident); sh_link = LoadUtil.little32(in); sh_info = LoadUtil.little32(in); sh_addralign = LoadUtil.loadXword(in, elf.e_ident); sh_entsize = LoadUtil.loadXword(in, elf.e_ident); } protected int store(OutputStream out) throws IOException { int cnt = 0; cnt += StoreUtil.little32(out, sh_name); cnt += StoreUtil.little32(out, sh_type); cnt += StoreUtil.storeXword(out, elf.e_ident, sh_flags); cnt += StoreUtil.storeAddr(out, elf.e_ident, sh_addr); cnt += StoreUtil.storeOff(out, elf.e_ident, sh_offset); cnt += StoreUtil.storeXword(out, elf.e_ident, sh_size); cnt += StoreUtil.little32(out, sh_link); cnt += StoreUtil.little32(out, sh_info); cnt += StoreUtil.storeXword(out, elf.e_ident, sh_addralign); cnt += StoreUtil.storeXword(out, elf.e_ident, sh_entsize); return cnt; } private void loadSymTab() throws IOException { if (!isSymTab()) throw new RuntimeException("Only valid for symbol table sections"); ByteArrayInputStream in = new ByteArrayInputStream(m_body); long cnt = (sh_size == 0) ? 0 : (sh_size / sh_entsize); m_symtab = new Vector<Symbol>(); for (long i = 0; i < cnt; i++) { m_symtab.addElement(new Symbol(elf, in)); } } private void storeSymTab() throws IOException { if (!isSymTab()) { throw new RuntimeException("Only valid for symbol table sections"); } ByteArrayOutputStream out = new ByteArrayOutputStream(); sh_size = sh_entsize * getNoSymbols(); for (int i = 0; i < getNoSymbols(); i++) { getSymbol(i).store(out); } m_body = out.toByteArray(); } private void loadRelTab() throws IOException { if (!isRelTab()) { throw new RuntimeException("Only valid for relocation table sections"); } ByteArrayInputStream in = new ByteArrayInputStream(m_body); long cnt = (sh_size == 0) ? 0 : (sh_size / sh_entsize); m_reltab = new Vector<Reloc>(); for (long i = 0; i < cnt; i++) { m_reltab.addElement(new Reloc(elf, in)); } } private void loadRelaTab() throws IOException { if (!isRelaTab()) { throw new RuntimeException("Only valid for relocation table sections"); } final ByteArrayInputStream in = new ByteArrayInputStream(m_body); final long cnt = (sh_size == 0) ? 0 : (sh_size / sh_entsize); m_reltab = new Vector<Reloc>(); for (long i = 0; i < cnt; i++) { m_reltab.addElement(new Reloca(elf, in)); } } private void storeRelTab() throws IOException { if (!isRelTab()) throw new RuntimeException("Only valid for relocation table sections"); ByteArrayOutputStream out = new ByteArrayOutputStream(); sh_size = sh_entsize * getNoRelocs(); for (int i = 0; i < getNoRelocs(); i++) { getReloc(i).store(out); } m_body = out.toByteArray(); } private void loadStrTab() throws IOException { if (!isStrTab()) throw new RuntimeException("Only valid for string table sections"); strTab = new StrTab(m_body, (int) sh_size); } private void storeStrTab() throws IOException { if (!isStrTab()) { throw new RuntimeException("Only valid for string table sections"); } m_body = strTab.toByteArray(); sh_size = m_body.length; } protected byte[] loadBody(RandomAccessFile in) throws IOException { if (m_body == null) { m_body = new byte[(int) sh_size]; in.seek(sh_offset); in.read(m_body); if (isSymTab()) { loadSymTab(); } else if (isStrTab()) { loadStrTab(); } else if (isRelTab()) { loadRelTab(); } else if (isRelaTab()) { loadRelaTab(); } } return m_body; } protected int storeBody(OutputStream out) throws IOException { return (m_body != null) ? StoreUtil.bytes(out, m_body) : 0; } protected int prepareStoreBody() throws IOException { if (isSymTab()) { storeSymTab(); } else if (isStrTab()) { storeStrTab(); } else if (isRelTab()) { storeRelTab(); } return (m_body != null) ? m_body.length : 0; } }