GP-4030: Fix MIPS base and eabi 32/64-bit cspecs

GP-4029: Update base PowerPC 32/64-bit cspecs
This commit is contained in:
ghintern 2025-02-25 20:50:19 +00:00 committed by James
parent 12ac4660a1
commit d91aebe74e
26 changed files with 1234 additions and 488 deletions

View file

@ -449,6 +449,16 @@
<attribute name="reversesignif">
<ref name="boolean_type"/>
</attribute>
</optional>
<optional>
<attribute name="stackspill">
<ref name="boolean_type"/>
</attribute>
</optional>
<optional>
<attribute name="fillalternate">
<ref name="boolean_type"/>
</attribute>
</optional>
<optional>
<attribute name="storage"/>
@ -461,6 +471,16 @@
</optional>
</element>
</choice>
<zeroOrMore>
<element name="extra_stack">
<optional>
<attribute name="afterbytes"/>
</optional>
<optional>
<attribute name="afterstorage"/>
</optional>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="consume_extra">
<attribute name="storage"/>
@ -474,13 +494,8 @@
<zeroOrMore>
<element name="consume_remaining">
<attribute name="storage"/>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="extra_stack">
<empty/>
</element>
</zeroOrMore>
</element>
</zeroOrMore>
</define>
<define name="prototype_type">

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -338,6 +338,22 @@ public class ParamEntry {
* @return slotnum plus the number of slots used
*/
public int getAddrBySlot(int slotnum, int sz, int typeAlign, ParameterPieces res) {
return getAddrBySlot(slotnum, sz, typeAlign, res, !isLeftJustified());
}
/**
* Assign the storage address when allocating something of size -sz- assuming -slotnum- slots
* have already been assigned. Set the address to null if the -sz- is too small or if
* there are not enough slots left
* @param slotnum number of slots already assigned
* @param sz number of bytes to being assigned
* @param typeAlign required byte alignment for the parameter
* @param res will hold the final storage address
* @param justifyRight true if initial bytes are padding for odd data-type sizes
* @return slotnum plus the number of slots used
*/
public int getAddrBySlot(int slotnum, int sz, int typeAlign, ParameterPieces res,
boolean justifyRight) {
int spaceused;
long offset;
res.address = null; // Start with an invalid result
@ -387,7 +403,7 @@ public class ParamEntry {
offset = addressbase + index * alignment;
slotnum += slotsused; // Inform caller of number of slots used
}
if (!isLeftJustified()) {
if (justifyRight) {
offset += (spaceused - sz);
}
res.address = spaceid.getAddress(offset);

View file

@ -15,15 +15,19 @@
*/
package ghidra.program.model.lang.protorules;
import static ghidra.program.model.pcode.AttributeId.*;
import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.lang.*;
import ghidra.program.model.pcode.Encoder;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.*;
/**
@ -37,6 +41,8 @@ import ghidra.xml.*;
public class ExtraStack extends AssignAction {
private ParamEntry stackEntry; // Parameter entry corresponding to the stack
private int afterBytes; // Activate side effect after given number of bytes consumed
private StorageClass afterStorage; // Active side effect after given amount of this storage consumed
/**
* Find stack entry in resource list
@ -64,17 +70,22 @@ public class ExtraStack extends AssignAction {
public ExtraStack(ParamListStandard res, int val) {
super(res);
stackEntry = null;
afterStorage = StorageClass.GENERAL;
afterBytes = -1;
}
public ExtraStack(ParamListStandard res) throws InvalidInputException {
public ExtraStack(StorageClass storage, int offset, ParamListStandard res)
throws InvalidInputException {
super(res);
stackEntry = null;
afterStorage = storage;
afterBytes = offset;
initializeEntry();
}
@Override
public AssignAction clone(ParamListStandard newResource) throws InvalidInputException {
return new ExtraStack(newResource);
return new ExtraStack(afterStorage, afterBytes, newResource);
}
@Override
@ -82,7 +93,13 @@ public class ExtraStack extends AssignAction {
if (this.getClass() != op.getClass()) {
return false;
}
ExtraStack otherAction = (ExtraStack) op;
if (afterBytes != otherAction.afterBytes || afterStorage != otherAction.afterStorage) {
return false;
}
return stackEntry.isEquivalent(otherAction.stackEntry);
}
@ -93,6 +110,21 @@ public class ExtraStack extends AssignAction {
return SUCCESS; // Parameter was already assigned to the stack
}
int grp = stackEntry.getGroup();
// Check whether we have consumed enough storage to need to adjust stack yet
if (afterBytes > 0) {
int bytesConsumed = 0;
for (int i = 0; i < resource.getNumParamEntry(); i++) {
if (i == grp || resource.getEntry(i).getType() != afterStorage) {
continue;
}
if (status[i] != 0) {
bytesConsumed += resource.getEntry(i).getSize();
}
}
if (bytesConsumed < afterBytes) {
return SUCCESS; // Don't yet need to consume extra stack space
}
}
// We assign the stack address (but ignore the actual address) updating the status for the stack,
// which consumes the stack resources.
ParameterPieces unused = new ParameterPieces();
@ -104,12 +136,34 @@ public class ExtraStack extends AssignAction {
@Override
public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_EXTRA_STACK);
if (afterBytes >= 0) {
encoder.writeUnsignedInteger(ATTRIB_AFTER_BYTES, afterBytes);
}
if (afterStorage != StorageClass.GENERAL) {
encoder.writeString(ATTRIB_STORAGE, afterStorage.toString());
}
encoder.closeElement(ELEM_EXTRA_STACK);
}
private void restoreAttributesXml(XmlElement el) throws XmlParseException {
Iterator<Entry<String, String>> iter = el.getAttributes().entrySet().iterator();
while (iter.hasNext()) {
Entry<String, String> attrib = iter.next();
String nm = attrib.getKey();
if (nm.equals(ATTRIB_AFTER_BYTES.name())) {
afterBytes = SpecXmlUtils.decodeInt(attrib.getValue());
}
else if (nm.equals(ATTRIB_AFTER_STORAGE.name())) {
afterStorage = StorageClass.getClass(attrib.getValue());
}
}
}
@Override
public void restoreXml(XmlPullParser parser) throws XmlParseException {
XmlElement elem = parser.start(ELEM_EXTRA_STACK.name());
restoreAttributesXml(elem);
parser.end(elem);
try {
initializeEntry();

View file

@ -227,7 +227,8 @@ public class MultiSlotAssign extends AssignAction {
return FAIL;
}
int grp = stackEntry.getGroup();
tmpStatus[grp] = stackEntry.getAddrBySlot(tmpStatus[grp], sizeLeft, align, param); // Consume all the space we need
tmpStatus[grp] =
stackEntry.getAddrBySlot(tmpStatus[grp], sizeLeft, align, param, justifyRight); // Consume all the space we need
if (param.address == null) {
return FAIL;
}

View file

@ -42,11 +42,14 @@ import ghidra.xml.*;
public class MultiSlotDualAssign extends AssignAction {
private StorageClass baseType; // Resource list from which to consume general tiles
private StorageClass altType; // Resource list from which to consume alternate tiles
private boolean consumeFromStack; // True if resources can be consumed from the stack
private boolean consumeMostSig; // True if resources are consumed starting with most significant bytes
private boolean justifyRight; // True if initial bytes are padding for odd data-type sizes
private boolean fillAlternate; // True if a single primitive needs to fill an alternate tile
private int tileSize; // Number of bytes in a tile
private ParamEntry[] baseTiles; // General registers for joining
private ParamEntry[] altTiles; // Alternate registers for joininig
private ParamEntry[] altTiles; // Alternate registers for joining
private ParamEntry stackEntry; // The stack resource
/**
* Find the first ParamEntry matching the baseType, and the first matching altType.
@ -55,6 +58,7 @@ public class MultiSlotDualAssign extends AssignAction {
private void initializeEntries() throws InvalidInputException {
baseTiles = resource.extractTiles(baseType);
altTiles = resource.extractTiles(altType);
stackEntry = resource.extractStack();
if (baseTiles.length == 0 || altTiles.length == 0) {
throw new InvalidInputException(
"Could not find matching resources for action: join_dual_class");
@ -64,6 +68,10 @@ public class MultiSlotDualAssign extends AssignAction {
throw new InvalidInputException(
"Storage class register sizes do not match for action: join_dual_class");
}
if (consumeFromStack && stackEntry == null) {
throw new InvalidInputException(
"Cannot find matching stack resource for action: join_dual_class");
}
}
/**
@ -101,6 +109,10 @@ public class MultiSlotDualAssign extends AssignAction {
int res = 1;
int count = 0;
int endBoundary = off + tileSize;
if (index[0] >= primitives.size()) {
return -1;
}
Primitive firstPrimitive = primitives.get(index[0]);
while (index[0] < primitives.size()) {
Primitive element = primitives.get(index[0]);
if (element.offset < off) {
@ -122,6 +134,14 @@ public class MultiSlotDualAssign extends AssignAction {
if (count == 0) {
return -1; // Must be at least one primitive in section
}
if (fillAlternate) { // Only use altType if the tile contains one primitive of exactly the tile size
if (count > 1) {
res = 0;
}
if (firstPrimitive.dt.getLength() != tileSize) {
res = 0;
}
}
return res;
}
@ -133,29 +153,47 @@ public class MultiSlotDualAssign extends AssignAction {
super(res);
baseType = StorageClass.GENERAL; // Tile from general purpose registers
altType = StorageClass.FLOAT; // Use specialized registers for floating-point components
consumeFromStack = false;
consumeMostSig = false;
justifyRight = false;
if (res.getEntry(0).isBigEndian()) {
consumeMostSig = true;
justifyRight = true;
}
fillAlternate = false;
tileSize = 0;
stackEntry = null;
}
public MultiSlotDualAssign(StorageClass baseStore, StorageClass altStore, boolean mostSig,
boolean justRight, ParamListStandard res) throws InvalidInputException {
/**
* Constructor
* @param baseStore resource list from which to consume general tiles
* @param altStore resource list form which to consume alternate tiles
* @param stack true if resources can be consumed from the stack
* @param mostSig true if resources are consumed starting with most significant bytes
* @param justRight true if initial bytes are padding for odd data-type sizes
* @param fillAlt true if a single primitive needs to fill an alternate tile
* @param res is the new resource set to associate with this action
* @throws InvalidInputException if the required elements are not available in the resource list
*/
public MultiSlotDualAssign(StorageClass baseStore, StorageClass altStore, boolean stack,
boolean mostSig, boolean justRight, boolean fillAlt, ParamListStandard res)
throws InvalidInputException {
super(res);
baseType = baseStore;
altType = altStore;
consumeFromStack = stack;
consumeMostSig = mostSig;
justifyRight = justRight;
fillAlternate = fillAlt;
stackEntry = null;
initializeEntries();
}
@Override
public AssignAction clone(ParamListStandard newResource) throws InvalidInputException {
return new MultiSlotDualAssign(baseType, altType, consumeMostSig, justifyRight,
newResource);
return new MultiSlotDualAssign(baseType, altType, consumeFromStack, consumeMostSig,
justifyRight, fillAlternate, newResource);
}
@Override
@ -164,8 +202,10 @@ public class MultiSlotDualAssign extends AssignAction {
return false;
}
MultiSlotDualAssign otherAction = (MultiSlotDualAssign) op;
if (consumeMostSig != otherAction.consumeMostSig ||
justifyRight != otherAction.justifyRight) {
if (consumeFromStack != otherAction.consumeFromStack ||
consumeMostSig != otherAction.consumeMostSig ||
justifyRight != otherAction.justifyRight ||
fillAlternate != otherAction.fillAlternate) {
return false;
}
if (baseType != otherAction.baseType || altType != otherAction.altType) {
@ -203,6 +243,7 @@ public class MultiSlotDualAssign extends AssignAction {
int[] tmpStatus = status.clone();
ArrayList<Varnode> pieces = new ArrayList<>();
int typeSize = dt.getLength();
int align = dt.getAlignment();
int sizeLeft = typeSize;
int iterBase = 0;
int iterAlt = 0;
@ -215,14 +256,20 @@ public class MultiSlotDualAssign extends AssignAction {
if (iterType == 0) {
iterBase = getFirstUnused(iterBase, baseTiles, tmpStatus);
if (iterBase == baseTiles.length) {
return FAIL; // Out of general registers
if (!consumeFromStack) {
return FAIL; // Out of general registers
}
break;
}
entry = baseTiles[iterBase];
}
else {
iterAlt = getFirstUnused(iterAlt, altTiles, tmpStatus);
if (iterAlt == altTiles.length) {
return FAIL; // Out of alternate registers
if (!consumeFromStack) {
return FAIL; // Out of alternate registers
}
break;
}
entry = altTiles[iterAlt];
}
@ -233,6 +280,19 @@ public class MultiSlotDualAssign extends AssignAction {
pieces.add(vn);
sizeLeft -= trialSize;
}
if (sizeLeft > 0) { // Have to use stack to get enough bytes
if (!consumeFromStack) {
return FAIL;
}
int grp = stackEntry.getGroup();
tmpStatus[grp] =
stackEntry.getAddrBySlot(tmpStatus[grp], sizeLeft, align, param, justifyRight);
if (param.address == null) {
return FAIL;
}
Varnode vn = new Varnode(param.address, sizeLeft);
pieces.add(vn);
}
if (sizeLeft < 0) { // Have odd data-type size
if (justifyRight) {
// Initial bytes of first entry are padding
@ -271,6 +331,8 @@ public class MultiSlotDualAssign extends AssignAction {
if (altType != StorageClass.FLOAT) {
encoder.writeString(ATTRIB_B, altType.toString());
}
encoder.writeBool(ATTRIB_STACKSPILL, consumeFromStack);
encoder.writeBool(ATTRIB_FILL_ALTERNATE, fillAlternate);
encoder.closeElement(ELEM_JOIN);
}
@ -295,6 +357,12 @@ public class MultiSlotDualAssign extends AssignAction {
else if (name.equals(ATTRIB_B.name())) {
altType = StorageClass.getClass(attrib.getValue());
}
else if (name.equals(ATTRIB_STACKSPILL.name())) {
consumeFromStack = SpecXmlUtils.decodeBoolean(attrib.getValue());
}
else if (name.equals(ATTRIB_FILL_ALTERNATE.name())) {
fillAlternate = SpecXmlUtils.decodeBoolean(attrib.getValue());
}
}
parser.end(elem);
try {

View file

@ -247,10 +247,13 @@ public record AttributeId(String name, int id) {
// modelrules
public static final AttributeId ATTRIB_SIZES = new AttributeId("sizes", 151);
public static final AttributeId ATTRIB_BACKFILL = new AttributeId("backfill", 152);
public static final AttributeId ATTRIB_MAX_PRIMITIVES = new AttributeId("maxprimitives", 153);
public static final AttributeId ATTRIB_REVERSESIGNIF = new AttributeId("reversesignif", 154);
public static final AttributeId ATTRIB_MATCHSIZE = new AttributeId("matchsize", 155);
public static final AttributeId ATTRIB_AFTER_BYTES = new AttributeId("afterbytes", 156);
public static final AttributeId ATTRIB_AFTER_STORAGE = new AttributeId("afterstorage", 157);
public static final AttributeId ATTRIB_FILL_ALTERNATE = new AttributeId("fillalternate", 158);
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 159);
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 156);
}