//-------------------------------------------------------------------------------------------------- // // @ CopyRight Roberti & Parau Enterprises, Inc. 2021-2023 // // This work is licensed under the Creative Commons Attribution-NoDerivatives 4.0 International License. // To view a copy of this license, visit http://creativecommons.org/licenses/by-nd/4.0/ // or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. // //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- // // Class containing the ELF section table with all the sections // //-------------------------------------------------------------------------------------------------- package framework; import java.math.BigInteger; import java.util.ArrayList; import java.util.LinkedList; public class DVSectionTable { protected DVSectionTable(DVAbi abi, DVSections sections, DVSymbols symbols, String inputFileName) { this.abi= abi; this.elfBits= abi.getElfBits(); this.elfEndianness= abi.getElfEndianness(); this.sections= sections; this.symbols= symbols; this.inputFileName= inputFileName; if (this.elfBits == 32) { this.elfHeaderLength= 52; this.sectionTableEntryLength= 40; this.relocationSectionEntryLength= 12; this.symbolTableEntryLength= 16; this.headerAlign= 4; this.symbolSectionAlign= 4; this.relocationSectionAlign= 4; } else { this.elfHeaderLength= 64; this.sectionTableEntryLength= 64; this.relocationSectionEntryLength= 24; this.symbolTableEntryLength= 24; this.headerAlign= 8; this.symbolSectionAlign= 8; this.relocationSectionAlign= 8; } this.symbolSection= new SymbolSection(); this.sectionTableList.add(new byte[this.sectionTableEntryLength]); } // // Return ELF binary // protected byte[] getElfBinary() { // // Build user sections // this.sections.buildBinaries(this); BigInteger stringSectionIndex= BigInteger.valueOf(this.maxIndex+1); BigInteger symbolSectionIndex= BigInteger.valueOf(this.maxIndex+2); // // Compute binary length // int totalLength= this.elfHeaderLength; // // Add user defined section lengths // for (ElfSection us : this.elfSectionList) { int align= us.align.intValue(); totalLength= ((totalLength+align-1)/align)*align; us.setOffset(totalLength); this.symbolSection.addSymbol(null, BigInteger.ZERO, BigInteger.ZERO, DVUtil.symbolBindLocal, DVUtil.symbolTypeSection, us.index); BigInteger nameIndex= this.sectionStringSection.addString(us.name); this.addSectionTableEntry(nameIndex, us.type, us.attribute, BigInteger.valueOf(totalLength), BigInteger.valueOf(us.binary.length), BigInteger.ZERO, BigInteger.ZERO, us.align, BigInteger.ZERO); if (us.attribute.equals(DVUtil.sectionTypeNobits)) continue; totalLength+= us.binary.length; if (us.relocationSection != null) { totalLength= ((totalLength+this.relocationSectionAlign-1)/ this.relocationSectionAlign)*this.relocationSectionAlign; us.relocationSection.setOffset(totalLength); nameIndex= this.sectionStringSection.addString(".rela" + us.name); this.addSectionTableEntry(nameIndex, DVUtil.sectionTypeRela, BigInteger.valueOf(this.abi.getRelocationSectionAttributes()), BigInteger.valueOf(totalLength), BigInteger.valueOf(this.relocationSectionEntryLength*us.relocationSection.relocationList.size()), symbolSectionIndex, us.index, BigInteger.valueOf(this.relocationSectionAlign), BigInteger.valueOf(this.relocationSectionEntryLength)); totalLength+= this.relocationSectionEntryLength*us.relocationSection.relocationList.size(); } } // // Fill in symbol table // this.symbols.fillElfSymbolSection(this.symbolSection, this.inputFileName); // // Add internally generated section lengths // int stringSectionOffset= totalLength; BigInteger nameIndex= this.sectionStringSection.addString(".strtab"); this.addSectionTableEntry(nameIndex, DVUtil.sectionTypeStrtab, BigInteger.ZERO, BigInteger.valueOf(totalLength), BigInteger.valueOf(this.stringSection.length), BigInteger.ZERO, BigInteger.ZERO, BigInteger.ONE, BigInteger.ZERO); totalLength+= this.stringSection.length; totalLength= ((totalLength+this.symbolSectionAlign-1)/ this.symbolSectionAlign)*this.symbolSectionAlign; int symbolSectionOffset= totalLength; nameIndex= this.sectionStringSection.addString(".symtab"); this.addSectionTableEntry(nameIndex, DVUtil.sectionTypeSymtab, BigInteger.ZERO, BigInteger.valueOf(totalLength), BigInteger.valueOf(this.symbolSection.length), stringSectionIndex, this.symbolSection.endLocalIndex, BigInteger.valueOf(this.symbolSectionAlign), BigInteger.valueOf(this.symbolTableEntryLength)); totalLength+= this.symbolSection.length; int sectionStringSectionOffset= totalLength; nameIndex= this.sectionStringSection.addString(".shstrtab"); this.addSectionTableEntry(nameIndex, DVUtil.sectionTypeStrtab, BigInteger.ZERO, BigInteger.valueOf(totalLength), BigInteger.valueOf(this.sectionStringSection.length), BigInteger.ZERO, BigInteger.ZERO, BigInteger.ONE, BigInteger.ZERO); totalLength+= this.sectionStringSection.length; // // Add section table length // totalLength= ((totalLength+this.headerAlign-1)/this.headerAlign)*this.headerAlign; int sectionTableOffset= totalLength; int sectionTableLength= this.sectionTableEntryLength*this.sectionTableList.size(); totalLength+= sectionTableLength; // // Allocate ELF binary array // byte[] elfBinary= new byte[totalLength]; // // Populate header // elfBinary[0]= 0x7F; elfBinary[1]= 'E'; elfBinary[2]= 'L'; elfBinary[3]= 'F'; int offset; if (this.elfBits == 32) { elfBinary[4]= 0x01; DVUtil.addCode(elfBinary, 32, BigInteger.valueOf(sectionTableOffset).toByteArray(), 4, 1, this.elfEndianness); DVUtil.addCode(elfBinary, 40, BigInteger.valueOf(52).toByteArray(), 2, 1, elfEndianness); offset= 36; } else { elfBinary[4]= 0x02; DVUtil.addCode(elfBinary, 40, BigInteger.valueOf(sectionTableOffset).toByteArray(), 8, 1, elfEndianness); DVUtil.addCode(elfBinary, 52, BigInteger.valueOf(64).toByteArray(), 2, 1, elfEndianness); offset= 48; } if (this.elfEndianness == DVUtil.Endianness.LITTLE) elfBinary[5]= 0x01; else elfBinary[5]= 0x02; elfBinary[6]= 0x01; elfBinary[7]= (byte) this.abi.getOsAbi(); elfBinary[8]= (byte) this.abi.getAbiVersion(); DVUtil.addCode(elfBinary, 16, BigInteger.valueOf(this.abi.getType()).toByteArray(), 2, 1, this.elfEndianness); DVUtil.addCode(elfBinary, 18, BigInteger.valueOf(this.abi.getMachine()).toByteArray(), 2, 1, this.elfEndianness); DVUtil.addCode(elfBinary, 20, BigInteger.valueOf(this.abi.getVersion()).toByteArray(), 4, 1, this.elfEndianness); // // Fill in the rest at different offsets // DVUtil.addCode(elfBinary, offset, BigInteger.valueOf(this.abi.getProcessorFlags()).toByteArray(), 4, 1, elfEndianness); DVUtil.addCode(elfBinary, offset+10, BigInteger.valueOf(sectionTableEntryLength).toByteArray(), 2, 1, elfEndianness); DVUtil.addCode(elfBinary, offset+12, BigInteger.valueOf(this.maxIndex+4).toByteArray(), 2, 1, elfEndianness); DVUtil.addCode(elfBinary, offset+14, BigInteger.valueOf(this.maxIndex+3).toByteArray(), 2, 1, elfEndianness); // // Copy all user sections // for (ElfSection us : this.elfSectionList) { if (us.attribute .equals(DVUtil.sectionTypeNobits)) continue; System.arraycopy(us.binary, 0, elfBinary, us.offset, us.binary.length); if (us.relocationSection != null) System.arraycopy(us.relocationSection.getBinary(), 0, elfBinary, us.relocationSection.offset, us.relocationSection.length); } // // Copy internally generated sections // ArrayList binaryArray= this.stringSection.getBinary(); offset= 0; for (int i= 0; i < binaryArray.size(); i++) { byte [] binary= binaryArray.get(i); System.arraycopy(binary, 0, elfBinary, stringSectionOffset+offset, binary.length); offset+= binary.length; } binaryArray= this.symbolSection.getSection(); offset= 0; for (int i= 0; i < binaryArray.size(); i++) { byte [] binary= binaryArray.get(i); System.arraycopy(binary, 0, elfBinary, symbolSectionOffset+offset, binary.length); offset+= binary.length; } binaryArray= this.sectionStringSection.getBinary(); offset= 0; for (int i= 0; i < binaryArray.size(); i++) { byte[] binary= binaryArray.get(i); System.arraycopy(binary, 0, elfBinary, sectionStringSectionOffset+offset, binary.length); offset+= binary.length; } // // Copy section table // offset= 0; for (int i= 0; i < sectionTableList.size(); i++) { byte [] binary= this.sectionTableList.get(i); System.arraycopy(binary, 0, elfBinary, sectionTableOffset+offset, binary.length); offset+= binary.length; } return elfBinary; } // // Add a section table entry // private void addSectionTableEntry(BigInteger nameIndex, BigInteger type, BigInteger flags, BigInteger offset, BigInteger size, BigInteger link, BigInteger info, BigInteger align, BigInteger entrySize) { byte [] entry= new byte[this.sectionTableEntryLength]; if (this.elfBits == 32) { DVUtil.addCode(entry, 0, nameIndex.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 4, type.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 8, flags.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 16, offset.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 20, size.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 24, link.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 28, info.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 32, align.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 36, entrySize.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); } else { DVUtil.addCode(entry, 0, nameIndex.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 4, type.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 8, flags.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 24, offset.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 32, size.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 40, link.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 44, info.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 48, align.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 56, entrySize.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); } this.sectionTableList.add(entry); } // // Start a user section // protected ElfSection startSection(String name, BigInteger type, BigInteger attribute, BigInteger align, int length) { return new ElfSection(name, type, attribute, align, length); } // // ELF section sub-class // public class ElfSection { private ElfSection(String name, BigInteger type, BigInteger attribute, BigInteger align, int length) { this.name= name; this.type= type; this.attribute= attribute; this.align= align; DVSectionTable.this.maxIndex++; this.index= BigInteger.valueOf(DVSectionTable.this.maxIndex); binary= new byte[length]; DVSectionTable.this.elfSectionList.add(this); } protected BigInteger getIndex() { return this.index; } protected void copyBytes(byte[] newBytes, int offset) { System.arraycopy(newBytes, 0, this.binary, offset, newBytes.length); } private void setOffset(int offset) { this.offset= offset; } protected void addRelocationSection( ArrayList relocationList) { DVSectionTable.this.maxIndex++; this.relocationSection= new RelocationSection(relocationList); } private final String name; private final BigInteger type; private final BigInteger attribute; private final BigInteger align; private final BigInteger index; private int offset; private RelocationSection relocationSection= null; private final byte[] binary; } // // String section // public class StringSection { protected StringSection() { stringList.add(new byte[1]); } protected BigInteger addString(String newString) { if (newString == null) return BigInteger.ZERO; int ret= this.length; this.length+= newString.length()+1; this.stringList.add((newString + "\0").getBytes()); return BigInteger.valueOf(ret); } protected ArrayList getBinary() { return this.stringList; } private int length= 1; private final ArrayList stringList= new ArrayList(); } // // Symbol section // public class SymbolSection { protected SymbolSection() { if (DVSectionTable.this.elfBits == 32) { this.binaryList.add(new byte[16]); this.length= 16; } else { this.binaryList.add(new byte[24]); this.length= 24; } } protected BigInteger addSymbol(String name, BigInteger value, BigInteger size, BigInteger bind, BigInteger type, BigInteger sectionIndex) { byte[] nameIndex= DVSectionTable.this.stringSection.addString(name).toByteArray(); byte[] info= type.or(bind.shiftLeft(4)).toByteArray(); if (DVSectionTable.this.elfBits == 32) { byte[] entry= new byte[16]; DVUtil.addCode(entry, 0, nameIndex, 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 4, value.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 8, size.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 12, info, 1, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 13, new byte[1], 1, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 14, sectionIndex.toByteArray(), 2, 1, DVSectionTable.this.elfEndianness); this.binaryList.add(entry); this.length+= 16; } else { byte[] entry= new byte[24]; DVUtil.addCode(entry, 0, nameIndex, 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 4, info, 1, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 5, new byte[1], 1, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 6, sectionIndex.toByteArray(), 2, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 8, value.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(entry, 16, size.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); this.binaryList.add(entry); this.length+= 24; } return BigInteger.valueOf(this.binaryList.size()-1); } protected void markLocal() { this.endLocalIndex= BigInteger.valueOf(this.binaryList.size()); } protected ArrayList getSection() { return this.binaryList; } private BigInteger endLocalIndex; private int length; private final ArrayList binaryList= new ArrayList(); } // // Relocation section // public class RelocationSection { protected RelocationSection(ArrayList relocationList) { this.index= BigInteger.valueOf(DVSectionTable.this.maxIndex); this.relocationList= relocationList; if (DVSectionTable.this.elfBits == 32) this.length= 12*(this.relocationList.size()); else this.length= 24*(this.relocationList.size()); } protected byte[] getBinary() { byte[] binary= new byte[this.length]; int offset= 0; for (DVSections.Section.Relocation relocation : this.relocationList) { BigInteger relocationID= BigInteger.valueOf(relocation.relocationID.ID); if (DVSectionTable.this.elfBits == 32) { DVUtil.addCode(binary, offset, relocation.offset.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(binary, 4, relocation.symbol.index.shiftLeft(8).or(relocationID).toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(binary, 8, relocation.addEnd.toByteArray(), 4, 1, DVSectionTable.this.elfEndianness); offset+= 16; } else { DVUtil.addCode(binary, offset, relocation.offset.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(binary, offset+8, relocation.symbol.index.shiftLeft(32).or(relocationID).toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); DVUtil.addCode(binary, offset+16, relocation.addEnd.toByteArray(), 8, 1, DVSectionTable.this.elfEndianness); offset+= 24; } } return binary; } private void setOffset(int offset) { this.offset= offset; } protected BigInteger length() { return BigInteger.valueOf(this.length); } private final ArrayList relocationList; private final BigInteger index; private int offset; private final int length; } // // DVSectionTable class fields // private final DVAbi abi; private final int elfBits; private final DVUtil.Endianness elfEndianness; private final DVSections sections; private final DVSymbols symbols; private final StringSection stringSection= new StringSection(); private final SymbolSection symbolSection; private final String inputFileName; private final int symbolSectionAlign; private final int relocationSectionAlign; private final int headerAlign; private final int elfHeaderLength; private final int sectionTableEntryLength; private final int relocationSectionEntryLength; private final int symbolTableEntryLength; private int maxIndex= 0; private final StringSection sectionStringSection= new StringSection(); private final ArrayList sectionTableList= new ArrayList(); private final ArrayList elfSectionList= new ArrayList(); }