GP-5851 Fix tiling truncations for odd data-type sizes in

MultiSlotAssign. Fix for big endian multi-slot return value.
This commit is contained in:
caheckman 2025-07-15 23:09:23 +00:00
parent eb7dbaa04f
commit f6495e4146
13 changed files with 280 additions and 89 deletions

View file

@ -167,6 +167,13 @@ public class ParamListStandard implements ParamList {
return entry[index];
}
/**
* @return true if resources are from a big endian address space
*/
public boolean isBigEndian() {
return entry[0].isBigEndian();
}
@Override
public void assignMap(PrototypePieces proto, DataTypeManager dtManager,
ArrayList<ParameterPieces> res, boolean addAutoParams) {

View file

@ -18,11 +18,14 @@ package ghidra.program.model.lang.protorules;
import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.program.model.address.Address;
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.program.model.pcode.Varnode;
import ghidra.util.exception.InvalidInputException;
import ghidra.xml.*;
@ -124,8 +127,7 @@ public abstract class AssignAction {
action = new HiddenReturnAssign(res, HIDDENRET_SPECIALREG);
}
else if (nm.equals(ELEM_JOIN_PER_PRIMITIVE.name())) {
boolean consumeMostSig = res.getEntry(0).isBigEndian();
action = new MultiMemberAssign(StorageClass.GENERAL, false, consumeMostSig, res);
action = new MultiMemberAssign(StorageClass.GENERAL, false, res.isBigEndian(), res);
}
else if (nm.equals(ELEM_JOIN_DUAL_CLASS.name())) {
action = new MultiSlotDualAssign(res);
@ -191,4 +193,20 @@ public abstract class AssignAction {
action.restoreXml(parser);
return action;
}
public static void justifyPieces(ArrayList<Varnode> pieces, int offset, boolean isBigEndian,
boolean consumeMostSig,
boolean justifyRight) {
boolean addOffset = isBigEndian ^ consumeMostSig ^ justifyRight;
int pos = justifyRight ? 0 : pieces.size() - 1;
Varnode vn = pieces.get(pos);
Address addr = vn.getAddress();
if (addOffset) {
addr = addr.add(offset);
}
int sz = vn.getSize() - offset;
vn = new Varnode(addr, sz);
pieces.set(pos, vn);
}
}

View file

@ -22,7 +22,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Map.Entry;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.lang.*;
@ -41,6 +40,7 @@ import ghidra.xml.*;
*/
public class MultiSlotAssign extends AssignAction {
private StorageClass resourceType; // Resource list from which to consume
private boolean isBigEndian; // True for big endian architectures
private boolean consumeFromStack; // True if resources should be consumed from the stack
private boolean consumeMostSig; // True if resources are consumed starting with most significant bytes
private boolean enforceAlignment; // True if register resources are discarded to match alignment
@ -74,6 +74,7 @@ public class MultiSlotAssign extends AssignAction {
*/
protected MultiSlotAssign(ParamListStandard res) {
super(res);
isBigEndian = res.isBigEndian();
resourceType = StorageClass.GENERAL; // Join general purpose registers
consumeFromStack = !(res instanceof ParamListStandardOut); // Spill into stack by default
consumeMostSig = false;
@ -81,7 +82,7 @@ public class MultiSlotAssign extends AssignAction {
justifyRight = false;
adjacentEntries = true;
allowBackfill = false;
if (res.getEntry(0).isBigEndian()) {
if (isBigEndian) {
consumeMostSig = true;
justifyRight = true;
}
@ -92,6 +93,7 @@ public class MultiSlotAssign extends AssignAction {
boolean justRight, boolean backfill, ParamListStandard res)
throws InvalidInputException {
super(res);
isBigEndian = res.isBigEndian();
resourceType = store;
consumeFromStack = stack;
consumeMostSig = mostSig;
@ -240,20 +242,8 @@ public class MultiSlotAssign extends AssignAction {
// Floating-point register holding extended lower precision value
onePieceJoin = true; // Treat as "join" of full size register
}
else if (justifyRight) {
// Initial bytes are padding
Varnode vn = pieces.get(0);
Address addr = vn.getAddress().add(-sizeLeft);
int sz = vn.getSize() + sizeLeft;
vn = new Varnode(addr, sz);
pieces.set(0, vn);
}
else {
int end = pieces.size() - 1;
Varnode vn = pieces.get(end);
int sz = vn.getSize() + sizeLeft;
vn = new Varnode(vn.getAddress(), sz);
pieces.set(end, vn);
justifyPieces(pieces, -sizeLeft, isBigEndian, consumeMostSig, justifyRight);
}
}
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
@ -265,10 +255,10 @@ public class MultiSlotAssign extends AssignAction {
@Override
public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_JOIN);
if (resource.getEntry(0).isBigEndian() != justifyRight) {
if (resource.isBigEndian() != justifyRight) {
encoder.writeBool(ATTRIB_REVERSEJUSTIFY, true);
}
if (resource.getEntry(0).isBigEndian() != consumeMostSig) {
if (resource.isBigEndian() != consumeMostSig) {
encoder.writeBool(ATTRIB_REVERSESIGNIF, true);
}
if (resourceType != StorageClass.GENERAL) {

View file

@ -22,7 +22,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Map.Entry;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.lang.*;
@ -42,6 +41,7 @@ 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 isBigEndian; // True for big endian architectures
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
@ -151,12 +151,13 @@ public class MultiSlotDualAssign extends AssignAction {
*/
protected MultiSlotDualAssign(ParamListStandard res) {
super(res);
isBigEndian = res.isBigEndian();
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()) {
if (isBigEndian) {
consumeMostSig = true;
justifyRight = true;
}
@ -180,6 +181,7 @@ public class MultiSlotDualAssign extends AssignAction {
boolean mostSig, boolean justRight, boolean fillAlt, ParamListStandard res)
throws InvalidInputException {
super(res);
isBigEndian = res.isBigEndian();
baseType = baseStore;
altType = altStore;
consumeFromStack = stack;
@ -294,21 +296,7 @@ public class MultiSlotDualAssign extends AssignAction {
pieces.add(vn);
}
if (sizeLeft < 0) { // Have odd data-type size
if (justifyRight) {
// Initial bytes of first entry are padding
Varnode vn = pieces.get(0);
Address addr = vn.getAddress().add(-sizeLeft);
int sz = vn.getSize() + sizeLeft;
vn = new Varnode(addr, sz);
pieces.set(0, vn);
}
else {
int end = pieces.size() - 1;
Varnode vn = pieces.get(end);
int sz = vn.getSize() + sizeLeft;
vn = new Varnode(vn.getAddress(), sz);
pieces.set(end, vn);
}
justifyPieces(pieces, -sizeLeft, isBigEndian, consumeMostSig, justifyRight);
}
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
res.type = dt;
@ -319,10 +307,10 @@ public class MultiSlotDualAssign extends AssignAction {
@Override
public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_JOIN_DUAL_CLASS);
if (resource.getEntry(0).isBigEndian() != justifyRight) {
if (resource.isBigEndian() != justifyRight) {
encoder.writeBool(ATTRIB_REVERSEJUSTIFY, true);
}
if (resource.getEntry(0).isBigEndian() != consumeMostSig) {
if (resource.isBigEndian() != consumeMostSig) {
encoder.writeBool(ATTRIB_REVERSESIGNIF, true);
}
if (baseType != StorageClass.GENERAL) {