mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 14:54:29 +08:00
GP-5160: Handle section alignment flags in COFF header
This commit is contained in:
@@ -175,8 +175,10 @@ public class SectionHeader implements StructConverter, ByteArrayConverter {
|
|||||||
* Align on 8192-byte boundary.
|
* Align on 8192-byte boundary.
|
||||||
*/
|
*/
|
||||||
public final static int IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000;
|
public final static int IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000;
|
||||||
// Unused = 0x00F00000;
|
/**
|
||||||
// public final static int IMAGE_SCN_ALIGN_MASK = 0x00F00000;
|
* Mask for alignment flags
|
||||||
|
*/
|
||||||
|
public final static int IMAGE_SCN_ALIGN_MASK = 0x00F00000;
|
||||||
/**
|
/**
|
||||||
* Section contains extended relocations.
|
* Section contains extended relocations.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -538,7 +538,7 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
|||||||
Map<CoffSectionHeader, Address> map) {
|
Map<CoffSectionHeader, Address> map) {
|
||||||
// 1. loop over all sections
|
// 1. loop over all sections
|
||||||
// put all sections not at 0 into address set
|
// put all sections not at 0 into address set
|
||||||
// put all sections at 0 into "totals" map
|
// put all sections at 0 into "totals" map, accounting for later alignment needs
|
||||||
// 2. look for space before minimum of taken addresses
|
// 2. look for space before minimum of taken addresses
|
||||||
// 3. or, look for space after maximum of taken addresses
|
// 3. or, look for space after maximum of taken addresses
|
||||||
|
|
||||||
@@ -548,24 +548,22 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
|||||||
|
|
||||||
AddressSet nonZeroSet = new AddressSet();
|
AddressSet nonZeroSet = new AddressSet();
|
||||||
|
|
||||||
int totalSize = 0;
|
int totalZeroSectionSize = 0;
|
||||||
TreeMap<String, Integer> zeroSectionSizes = new TreeMap<>();
|
Map<String, Integer> zeroSectionSizes = new TreeMap<>();
|
||||||
TreeMap<String, Integer> zeroSectionOffsets = new TreeMap<>();
|
Map<String, Integer> zeroSectionOffsets = new TreeMap<>();
|
||||||
|
|
||||||
List<CoffSectionHeader> sections = header.getSections();
|
List<CoffSectionHeader> sections = header.getSections();
|
||||||
for (CoffSectionHeader section : sections) {
|
for (CoffSectionHeader section : sections) {
|
||||||
int physicalAddress = section.getPhysicalAddress();
|
int physicalAddress = section.getPhysicalAddress();
|
||||||
int size = section.getSize(language);
|
int size = section.getSize(language);
|
||||||
if (physicalAddress == 0) {
|
if (physicalAddress == 0) {
|
||||||
|
// We don't know the exact offset now, so assume worst-case alignment penalty
|
||||||
|
int alignedSize = size + getSectionAlignment(section) - 1;
|
||||||
String name = section.getName();
|
String name = section.getName();
|
||||||
Integer s = zeroSectionSizes.get(name);
|
zeroSectionSizes.compute(name,
|
||||||
if (s == null) {
|
(k, v) -> (v == null ? alignedSize : v + alignedSize));
|
||||||
zeroSectionSizes.put(name, size);
|
|
||||||
}
|
totalZeroSectionSize += alignedSize;
|
||||||
else {
|
|
||||||
zeroSectionSizes.put(name, s + size);
|
|
||||||
}
|
|
||||||
totalSize += size;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
@@ -579,35 +577,47 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Address maxAddress = nonZeroSet.getMaxAddress();
|
Address maxAddress = nonZeroSet.getMaxAddress();
|
||||||
int offset = (maxAddress == null ? EMPTY_START_OFFSET - 1
|
int offset = (maxAddress == null ? EMPTY_START_OFFSET - 1
|
||||||
: (int) (maxAddress.getOffset() & 0xffffffff));
|
: (int) (maxAddress.getOffset() & 0xffffffff));
|
||||||
long sum = offset;
|
long sum = offset;
|
||||||
sum += totalSize;
|
sum += totalZeroSectionSize;
|
||||||
if (sum <= 0x100000000L) {
|
if (sum <= 0x100000000L) {
|
||||||
int start = align(offset + 1);
|
offset += 1;
|
||||||
|
// Each group of sections with the same name should be aligned at least at 256 bytes
|
||||||
for (Entry<String, Integer> entry : zeroSectionSizes.entrySet()) {
|
for (Entry<String, Integer> entry : zeroSectionSizes.entrySet()) {
|
||||||
zeroSectionOffsets.put(entry.getKey(), start);
|
offset = (offset + DEFAULT_ALIGNMENT - 1) / DEFAULT_ALIGNMENT * DEFAULT_ALIGNMENT;
|
||||||
start = align(start + entry.getValue());
|
zeroSectionOffsets.put(entry.getKey(), offset);
|
||||||
|
offset += zeroSectionSizes.get(entry.getKey());
|
||||||
}
|
}
|
||||||
int sectionNumber = 1;
|
int sectionNumber = 1;
|
||||||
for (CoffSectionHeader section : sections) {
|
for (CoffSectionHeader section : sections) {
|
||||||
int physicalAddress = section.getPhysicalAddress();
|
int physicalAddress = section.getPhysicalAddress();
|
||||||
if (physicalAddress == 0) {
|
if (physicalAddress == 0) {
|
||||||
String name = section.getName();
|
String name = section.getName();
|
||||||
start = zeroSectionOffsets.get(name);
|
int alignment = getSectionAlignment(section);
|
||||||
relocateSection(header, section, sectionNumber, start);
|
offset = (zeroSectionOffsets.get(name) + alignment - 1) / alignment * alignment;
|
||||||
zeroSectionOffsets.put(name, start + section.getSize(language));
|
relocateSection(header, section, sectionNumber, offset);
|
||||||
|
zeroSectionOffsets.put(name, offset + section.getSize(language));
|
||||||
}
|
}
|
||||||
++sectionNumber;
|
++sectionNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int ALIGNMENT = 0x100;
|
private static final int DEFAULT_ALIGNMENT = 0x100;
|
||||||
|
|
||||||
private int align(int i) {
|
/**
|
||||||
return (i + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT;
|
* Query a section header for alignment information. The base version of this method assumes
|
||||||
|
* no alignment information is stored in the section header. Subclasses may implement a
|
||||||
|
* platform-specific check for alignment information.
|
||||||
|
*
|
||||||
|
* @param section header object for the section
|
||||||
|
* @return the alignment requested by the section
|
||||||
|
*/
|
||||||
|
protected int getSectionAlignment(CoffSectionHeader section) {
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void relocateSection(CoffFileHeader header, CoffSectionHeader section,
|
private void relocateSection(CoffFileHeader header, CoffSectionHeader section,
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.opinion;
|
package ghidra.app.util.opinion;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.coff.CoffSectionHeader;
|
||||||
|
import ghidra.app.util.bin.format.pe.SectionHeader;
|
||||||
|
|
||||||
public class MSCoffLoader extends CoffLoader {
|
public class MSCoffLoader extends CoffLoader {
|
||||||
public final static String MSCOFF_NAME = "MS Common Object File Format (COFF)";
|
public final static String MSCOFF_NAME = "MS Common Object File Format (COFF)";
|
||||||
|
|
||||||
@@ -33,4 +36,15 @@ public class MSCoffLoader extends CoffLoader {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getSectionAlignment(CoffSectionHeader section) {
|
||||||
|
// Alignment is packed as a 4-bit integer in the flags, value 2^(align_bits - 1)
|
||||||
|
int s_flags = section.getFlags();
|
||||||
|
int align_bits = (s_flags & SectionHeader.IMAGE_SCN_ALIGN_MASK) >> 20;
|
||||||
|
if (align_bits == 0 || align_bits >= 0xF) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 1 << (align_bits - 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user