mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-1871 Overlapping pentry tags
This commit is contained in:
parent
da697acbb5
commit
716dfb1690
7 changed files with 282 additions and 179 deletions
|
@ -56,32 +56,72 @@ void ParamEntry::resolveJoin(list<ParamEntry> &curList)
|
||||||
int4 max = entry->group + entry->groupsize;
|
int4 max = entry->group + entry->groupsize;
|
||||||
if (max > maxgrp)
|
if (max > maxgrp)
|
||||||
maxgrp = max;
|
maxgrp = max;
|
||||||
|
// For output <pentry>, if the most signifigant part overlaps with an earlier <pentry>
|
||||||
|
// the least signifigant part is marked for extra checks, and vice versa.
|
||||||
|
flags |= (i==0) ? extracheck_low : extracheck_high;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (maxgrp < 0 || mingrp >= 1000)
|
if (maxgrp < 0 || mingrp >= 1000)
|
||||||
throw LowlevelError("<pentry> join must overlap at least one previous entry");
|
throw LowlevelError("<pentry> join must overlap at least one previous entry");
|
||||||
group = mingrp;
|
group = mingrp;
|
||||||
groupsize = (maxgrp - mingrp);
|
groupsize = (maxgrp - mingrp);
|
||||||
|
flags |= overlapping;
|
||||||
if (groupsize > joinrec->numPieces())
|
if (groupsize > joinrec->numPieces())
|
||||||
throw LowlevelError("<pentry> join must overlap sequential entries");
|
throw LowlevelError("<pentry> join must overlap sequential entries");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A ParamEntry with \e join storage must either overlap a single other ParamEntry or
|
/// Search for overlaps of \b this with any previous entry. If an overlap is discovered,
|
||||||
/// all pieces must overlap.
|
/// verify the form is correct for the different ParamEntry to share \e group slots and
|
||||||
/// \return \b true if \b this is a join whose pieces do not all overlap
|
/// reassign \b this group.
|
||||||
bool ParamEntry::isNonOverlappingJoin(void) const
|
/// \param curList is the list of previous entries
|
||||||
|
void ParamEntry::resolveOverlap(list<ParamEntry> &curList)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (joinrec == (JoinRecord *)0)
|
if (joinrec != (JoinRecord *)0)
|
||||||
return false;
|
return; // Overlaps with join records dealt with in resolveJoin
|
||||||
return (joinrec->numPieces() != groupsize);
|
int4 grpsize = 0;
|
||||||
|
int4 mingrp = 1000;
|
||||||
|
int4 maxgrp = -1;
|
||||||
|
list<ParamEntry>::const_iterator iter,enditer;
|
||||||
|
Address addr(spaceid,addressbase);
|
||||||
|
enditer = curList.end();
|
||||||
|
--enditer; // The last entry is \b this ParamEntry
|
||||||
|
for(iter=curList.begin();iter!=enditer;++iter) {
|
||||||
|
const ParamEntry &entry(*iter);
|
||||||
|
if (!entry.intersects(addr, size)) continue;
|
||||||
|
if (contains(entry)) { // If this contains the intersecting entry
|
||||||
|
if (entry.isOverlap()) continue; // Don't count resources (already counted overlapped entry)
|
||||||
|
if (entry.group < mingrp)
|
||||||
|
mingrp = entry.group;
|
||||||
|
int4 max = entry.group + entry.groupsize;
|
||||||
|
if (max > maxgrp)
|
||||||
|
maxgrp = max;
|
||||||
|
grpsize += entry.groupsize;
|
||||||
|
// For output <pentry>, if the most signifigant part overlaps with an earlier <pentry>
|
||||||
|
// the least signifigant part is marked for extra checks, and vice versa.
|
||||||
|
if (addressbase == entry.addressbase)
|
||||||
|
flags |= spaceid->isBigEndian() ? extracheck_low : extracheck_high;
|
||||||
|
else
|
||||||
|
flags |= spaceid->isBigEndian() ? extracheck_high : extracheck_low;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw LowlevelError("Illegal overlap of <pentry> in compiler spec");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grpsize == 0) return; // No overlaps
|
||||||
|
if (grpsize != (maxgrp - mingrp))
|
||||||
|
throw LowlevelError("<pentry> must overlap sequential entries");
|
||||||
|
group = mingrp;
|
||||||
|
groupsize = grpsize;
|
||||||
|
flags |= overlapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This entry must properly contain the other memory range, and
|
/// This entry must properly contain the other memory range, and
|
||||||
/// the entry properties must be compatible.
|
/// the entry properties must be compatible. A \e join ParamEntry can
|
||||||
/// \param op2 is the other entry to compare with \b this
|
/// subsume another \e join ParamEntry, but we expect the addressbase to be identical.
|
||||||
/// \return \b true if the other entry is contained
|
/// \param op2 is the given entry to compare with \b this
|
||||||
bool ParamEntry::contains(const ParamEntry &op2) const
|
/// \return \b true if the given entry is subsumed
|
||||||
|
bool ParamEntry::subsumesDefinition(const ParamEntry &op2) const
|
||||||
|
|
||||||
{
|
{
|
||||||
if ((type!=TYPE_UNKNOWN)&&(op2.type != type)) return false;
|
if ((type!=TYPE_UNKNOWN)&&(op2.type != type)) return false;
|
||||||
|
@ -92,6 +132,7 @@ bool ParamEntry::contains(const ParamEntry &op2) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// We assume a \e join ParamEntry cannot be contained by a single contiguous memory range.
|
||||||
/// \param addr is the starting address of the potential containing range
|
/// \param addr is the starting address of the potential containing range
|
||||||
/// \param sz is the number of bytes in the range
|
/// \param sz is the number of bytes in the range
|
||||||
/// \return \b true if the entire ParamEntry fits inside the range
|
/// \return \b true if the entire ParamEntry fits inside the range
|
||||||
|
@ -105,6 +146,38 @@ bool ParamEntry::containedBy(const Address &addr,int4 sz) const
|
||||||
return (entryoff <= rangeoff);
|
return (entryoff <= rangeoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If \b this a a \e join, each piece is tested for intersection.
|
||||||
|
/// Otherwise, \b this, considered as a single memory, is tested for intersection.
|
||||||
|
/// \param addr is the starting address of the given memory range to test against
|
||||||
|
/// \param sz is the number of bytes in the given memory range
|
||||||
|
/// \return \b true if there is any kind of intersection
|
||||||
|
bool ParamEntry::intersects(const Address &addr,int4 sz) const
|
||||||
|
|
||||||
|
{
|
||||||
|
uintb rangeend;
|
||||||
|
if (joinrec != (JoinRecord *)0) {
|
||||||
|
rangeend = addr.getOffset() + sz - 1;
|
||||||
|
for(int4 i=0;i<joinrec->numPieces();++i) {
|
||||||
|
const VarnodeData &vdata( joinrec->getPiece(i) );
|
||||||
|
if (addr.getSpace() != vdata.space) continue;
|
||||||
|
uintb vdataend = vdata.offset + vdata.size - 1;
|
||||||
|
if (addr.getOffset() < vdata.offset && rangeend < vdataend)
|
||||||
|
continue;
|
||||||
|
if (addr.getOffset() > vdata.offset && rangeend > vdataend)
|
||||||
|
continue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (spaceid != addr.getSpace()) return false;
|
||||||
|
rangeend = addr.getOffset() + sz - 1;
|
||||||
|
uintb thisend = addressbase + size - 1;
|
||||||
|
if (addr.getOffset() < addressbase && rangeend < thisend)
|
||||||
|
return false;
|
||||||
|
if (addr.getOffset() > addressbase && rangeend > thisend)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if the given memory range is contained in \b this.
|
/// Check if the given memory range is contained in \b this.
|
||||||
/// If it is contained, return the endian aware offset of the containment.
|
/// If it is contained, return the endian aware offset of the containment.
|
||||||
/// I.e. if the least significant byte of the given range falls on the least significant
|
/// I.e. if the least significant byte of the given range falls on the least significant
|
||||||
|
@ -194,6 +267,28 @@ bool ParamEntry::getContainer(const Address &addr,int4 sz,VarnodeData &res) cons
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test that \b this, as one or more memory ranges, contains the other ParamEntry's memory range.
|
||||||
|
/// A \e join ParamEntry cannot be contained by another entry, but it can contain an entry in one
|
||||||
|
/// of its pieces.
|
||||||
|
/// \param op2 is the given ParamEntry to test for containment
|
||||||
|
/// \return \b true if the given ParamEntry is contained
|
||||||
|
bool ParamEntry::contains(const ParamEntry &op2) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (op2.joinrec != (JoinRecord *)0) return false; // Assume a join entry cannot be contained
|
||||||
|
if (joinrec == (JoinRecord *)0) {
|
||||||
|
Address addr(spaceid,addressbase);
|
||||||
|
return op2.containedBy(addr, size);
|
||||||
|
}
|
||||||
|
for(int4 i=0;i<joinrec->numPieces();++i) {
|
||||||
|
const VarnodeData &vdata(joinrec->getPiece(i));
|
||||||
|
Address addr = vdata.getAddr();
|
||||||
|
if (op2.containedBy(addr,vdata.size))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Calculate the type of \e extension to expect for the given logical value
|
/// \brief Calculate the type of \e extension to expect for the given logical value
|
||||||
///
|
///
|
||||||
/// Return:
|
/// Return:
|
||||||
|
@ -402,54 +497,7 @@ void ParamEntry::restoreXml(const Element *el,const AddrSpaceManager *manage,boo
|
||||||
if (grouped)
|
if (grouped)
|
||||||
flags |= is_grouped;
|
flags |= is_grouped;
|
||||||
resolveJoin(curList);
|
resolveJoin(curList);
|
||||||
}
|
resolveOverlap(curList);
|
||||||
|
|
||||||
/// \brief Check if \b this entry represents a \e joined parameter and requires extra scrutiny
|
|
||||||
///
|
|
||||||
/// Return value parameter lists allow overlapping entries if one of the overlapping entries
|
|
||||||
/// is a \e joined parameter. In this case the return value recovery logic needs to know
|
|
||||||
/// what portion(s) of the joined parameter are overlapped. This method sets flags on \b this
|
|
||||||
/// to indicate the overlap.
|
|
||||||
/// \param entry is the full parameter list to check for overlaps with \b this
|
|
||||||
void ParamEntry::extraChecks(list<ParamEntry> &entry)
|
|
||||||
|
|
||||||
{
|
|
||||||
if (joinrec == (JoinRecord *)0) return; // Nothing to do if not multiprecision
|
|
||||||
if (joinrec->numPieces() != 2) return;
|
|
||||||
const VarnodeData &highPiece(joinrec->getPiece(0));
|
|
||||||
bool seenOnce = false;
|
|
||||||
list<ParamEntry>::const_iterator iter;
|
|
||||||
for(iter=entry.begin();iter!=entry.end();++iter) { // Search for high piece, used as whole/low in another entry
|
|
||||||
AddrSpace *spc = (*iter).getSpace();
|
|
||||||
uintb off = (*iter).getBase();
|
|
||||||
int4 sz = (*iter).getSize();
|
|
||||||
if ((highPiece.offset == off)&&(highPiece.space == spc)&&(highPiece.size == sz)) {
|
|
||||||
if (seenOnce) throw LowlevelError("Extra check hits twice");
|
|
||||||
seenOnce = true;
|
|
||||||
flags |= extracheck_low; // If found, we must do extra checks on the low
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!seenOnce)
|
|
||||||
flags |= extracheck_high; // The default is to do extra checks on the high
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the storage is in the \e join space, we count the number of join pieces that overlap something
|
|
||||||
/// in the given list of entries.
|
|
||||||
/// \param curList is the list of entries to check
|
|
||||||
/// \return the number of overlapping pieces
|
|
||||||
int4 ParamEntry::countJoinOverlap(const list<ParamEntry> &curList) const
|
|
||||||
|
|
||||||
{
|
|
||||||
if (joinrec == (JoinRecord *)0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
for (int4 i=0;i<joinrec->numPieces();++i) {
|
|
||||||
const ParamEntry *match = findEntryByStorage(curList, joinrec->getPiece(i));
|
|
||||||
if (match != (const ParamEntry *)0)
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Entries within a group must be distinguishable by size or by type.
|
/// Entries within a group must be distinguishable by size or by type.
|
||||||
|
@ -1176,15 +1224,6 @@ void ParamListStandard::restoreXml(const Element *el,const AddrSpaceManager *man
|
||||||
parseGroup(subel, manage, effectlist, numgroup, normalstack, autokilledbycall, splitFloat);
|
parseGroup(subel, manage, effectlist, numgroup, normalstack, autokilledbycall, splitFloat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check that any pentry tags with join storage don't overlap following tags
|
|
||||||
for (list<ParamEntry>::const_iterator eiter=entry.begin();eiter!=entry.end();++eiter) {
|
|
||||||
const ParamEntry &curEntry( *eiter );
|
|
||||||
if (curEntry.isNonOverlappingJoin()) {
|
|
||||||
if (curEntry.countJoinOverlap(entry) != 1) {
|
|
||||||
throw LowlevelError("pentry tag must be listed after all its overlaps");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
calcDelay();
|
calcDelay();
|
||||||
populateResolver();
|
populateResolver();
|
||||||
}
|
}
|
||||||
|
@ -1302,17 +1341,6 @@ bool ParamListRegisterOut::possibleParam(const Address &loc,int4 size) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParamListRegisterOut::restoreXml(const Element *el,const AddrSpaceManager *manage,
|
|
||||||
vector<EffectRecord> &effectlist,bool normalstack)
|
|
||||||
{
|
|
||||||
ParamListStandard::restoreXml(el,manage,effectlist,normalstack);
|
|
||||||
list<ParamEntry>::iterator iter;
|
|
||||||
for(iter=entry.begin();iter!=entry.end();++iter) {
|
|
||||||
ParamEntry &curEntry(*iter);
|
|
||||||
curEntry.extraChecks(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParamList *ParamListRegisterOut::clone(void) const
|
ParamList *ParamListRegisterOut::clone(void) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1427,11 +1455,11 @@ void ParamListMerged::foldIn(const ParamListStandard &op2)
|
||||||
int4 typeint = 0;
|
int4 typeint = 0;
|
||||||
list<ParamEntry>::iterator iter;
|
list<ParamEntry>::iterator iter;
|
||||||
for(iter=entry.begin();iter!=entry.end();++iter) {
|
for(iter=entry.begin();iter!=entry.end();++iter) {
|
||||||
if ((*iter).contains(opentry)) {
|
if ((*iter).subsumesDefinition(opentry)) {
|
||||||
typeint = 2;
|
typeint = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opentry.contains( *iter )) {
|
if (opentry.subsumesDefinition( *iter )) {
|
||||||
typeint = 1;
|
typeint = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,8 @@ public:
|
||||||
smallsize_floatext = 64, ///< Assume values smaller than max \b size are floating-point extended to full size
|
smallsize_floatext = 64, ///< Assume values smaller than max \b size are floating-point extended to full size
|
||||||
extracheck_high = 128, ///< Perform extra checks during parameter recovery on most sig portion of the double
|
extracheck_high = 128, ///< Perform extra checks during parameter recovery on most sig portion of the double
|
||||||
extracheck_low = 256, ///< Perform extra checks during parameter recovery on least sig portion of the double
|
extracheck_low = 256, ///< Perform extra checks during parameter recovery on least sig portion of the double
|
||||||
is_grouped = 512 ///< This entry is grouped with other entries
|
is_grouped = 512, ///< This entry is grouped with other entries
|
||||||
|
overlapping = 0x100 ///< Overlaps an earlier entry (and doesn't consume additional resource slots)
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
uint4 flags; ///< Boolean properties of the parameter
|
uint4 flags; ///< Boolean properties of the parameter
|
||||||
|
@ -73,6 +74,7 @@ private:
|
||||||
JoinRecord *joinrec; ///< Non-null if this is logical variable from joined pieces
|
JoinRecord *joinrec; ///< Non-null if this is logical variable from joined pieces
|
||||||
static const ParamEntry *findEntryByStorage(const list<ParamEntry> &entryList,const VarnodeData &vn);
|
static const ParamEntry *findEntryByStorage(const list<ParamEntry> &entryList,const VarnodeData &vn);
|
||||||
void resolveJoin(list<ParamEntry> &curList); ///< Make adjustments for a \e join ParamEntry
|
void resolveJoin(list<ParamEntry> &curList); ///< Make adjustments for a \e join ParamEntry
|
||||||
|
void resolveOverlap(list<ParamEntry> &curList); ///< Make adjustments for ParamEntry that overlaps others
|
||||||
|
|
||||||
/// \brief Is the logical value left-justified within its container
|
/// \brief Is the logical value left-justified within its container
|
||||||
bool isLeftJustified(void) const { return (((flags&force_left_justify)!=0)||(!spaceid->isBigEndian())); }
|
bool isLeftJustified(void) const { return (((flags&force_left_justify)!=0)||(!spaceid->isBigEndian())); }
|
||||||
|
@ -87,21 +89,21 @@ public:
|
||||||
bool isExclusion(void) const { return (alignment==0); } ///< Return \b true if this holds a single parameter exclusively
|
bool isExclusion(void) const { return (alignment==0); } ///< Return \b true if this holds a single parameter exclusively
|
||||||
bool isReverseStack(void) const { return ((flags & reverse_stack)!=0); } ///< Return \b true if parameters are allocated in reverse order
|
bool isReverseStack(void) const { return ((flags & reverse_stack)!=0); } ///< Return \b true if parameters are allocated in reverse order
|
||||||
bool isGrouped(void) const { return ((flags & is_grouped)!=0); } ///< Return \b true if \b this is grouped with other entries
|
bool isGrouped(void) const { return ((flags & is_grouped)!=0); } ///< Return \b true if \b this is grouped with other entries
|
||||||
bool isNonOverlappingJoin(void) const; ///< Return \b true if not all pieces overlap other ParamEntry tags
|
bool isOverlap(void) const { return ((flags & overlapping)!=0); } ///< Return \b true if \b this overlaps another entry
|
||||||
bool contains(const ParamEntry &op2) const; ///< Does \b this contain the indicated entry.
|
bool subsumesDefinition(const ParamEntry &op2) const; ///< Does \b this subsume the definition of the given ParamEntry
|
||||||
bool containedBy(const Address &addr,int4 sz) const; ///< Is this entry contained by the given range
|
bool containedBy(const Address &addr,int4 sz) const; ///< Is this entry contained by the given range
|
||||||
|
bool intersects(const Address &addr,int4 sz) const; ///< Does \b this intersect the given range in some way
|
||||||
int4 justifiedContain(const Address &addr,int4 sz) const; ///< Calculate endian aware containment
|
int4 justifiedContain(const Address &addr,int4 sz) const; ///< Calculate endian aware containment
|
||||||
bool getContainer(const Address &addr,int4 sz,VarnodeData &res) const;
|
bool getContainer(const Address &addr,int4 sz,VarnodeData &res) const;
|
||||||
|
bool contains(const ParamEntry &op2) const; ///< Does \this contain the given entry (as a subpiece)
|
||||||
OpCode assumedExtension(const Address &addr,int4 sz,VarnodeData &res) const;
|
OpCode assumedExtension(const Address &addr,int4 sz,VarnodeData &res) const;
|
||||||
int4 getSlot(const Address &addr,int4 skip) const;
|
int4 getSlot(const Address &addr,int4 skip) const;
|
||||||
AddrSpace *getSpace(void) const { return spaceid; } ///< Get the address space containing \b this entry
|
AddrSpace *getSpace(void) const { return spaceid; } ///< Get the address space containing \b this entry
|
||||||
uintb getBase(void) const { return addressbase; } ///< Get the starting offset of \b this entry
|
uintb getBase(void) const { return addressbase; } ///< Get the starting offset of \b this entry
|
||||||
Address getAddrBySlot(int4 &slot,int4 sz) const;
|
Address getAddrBySlot(int4 &slot,int4 sz) const;
|
||||||
void restoreXml(const Element *el,const AddrSpaceManager *manage,bool normalstack,bool grouped,list<ParamEntry> &curList);
|
void restoreXml(const Element *el,const AddrSpaceManager *manage,bool normalstack,bool grouped,list<ParamEntry> &curList);
|
||||||
void extraChecks(list<ParamEntry> &entry);
|
|
||||||
bool isParamCheckHigh(void) const { return ((flags & extracheck_high)!=0); } ///< Return \b true if there is a high overlap
|
bool isParamCheckHigh(void) const { return ((flags & extracheck_high)!=0); } ///< Return \b true if there is a high overlap
|
||||||
bool isParamCheckLow(void) const { return ((flags & extracheck_low)!=0); } ///< Return \b true if there is a low overlap
|
bool isParamCheckLow(void) const { return ((flags & extracheck_low)!=0); } ///< Return \b true if there is a low overlap
|
||||||
int4 countJoinOverlap(const list<ParamEntry> &curList) const; ///< Count the number of other entries \b this overlaps
|
|
||||||
static void orderWithinGroup(const ParamEntry &entry1,const ParamEntry &entry2); ///< Enforce ParamEntry group ordering rules
|
static void orderWithinGroup(const ParamEntry &entry1,const ParamEntry &entry2); ///< Enforce ParamEntry group ordering rules
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -561,7 +563,6 @@ public:
|
||||||
virtual void assignMap(const vector<Datatype *> &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const;
|
virtual void assignMap(const vector<Datatype *> &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const;
|
||||||
virtual void fillinMap(ParamActive *active) const;
|
virtual void fillinMap(ParamActive *active) const;
|
||||||
virtual bool possibleParam(const Address &loc,int4 size) const;
|
virtual bool possibleParam(const Address &loc,int4 size) const;
|
||||||
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack);
|
|
||||||
virtual ParamList *clone(void) const;
|
virtual ParamList *clone(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class ParamEntry {
|
||||||
//private static final int EXTRACHECK_HIGH = 128;
|
//private static final int EXTRACHECK_HIGH = 128;
|
||||||
//private static final int EXTRACHECK_LOW = 256;
|
//private static final int EXTRACHECK_LOW = 256;
|
||||||
private static final int IS_GROUPED = 512; // The entry is grouped with other entries
|
private static final int IS_GROUPED = 512; // The entry is grouped with other entries
|
||||||
|
private static final int OVERLAPPING = 0x100; // This overlaps an earlier entry
|
||||||
|
|
||||||
public static final int TYPE_UNKNOWN = 8; // Default type restriction
|
public static final int TYPE_UNKNOWN = 8; // Default type restriction
|
||||||
public static final int TYPE_PTR = 2; // pointer types
|
public static final int TYPE_PTR = 2; // pointer types
|
||||||
|
@ -100,6 +101,10 @@ public class ParamEntry {
|
||||||
return ((flags & IS_GROUPED) != 0);
|
return ((flags & IS_GROUPED) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOverlap() {
|
||||||
|
return ((flags & OVERLAPPING) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isBigEndian() {
|
public boolean isBigEndian() {
|
||||||
return ((flags & IS_BIG_ENDIAN) != 0);
|
return ((flags & IS_BIG_ENDIAN) != 0);
|
||||||
}
|
}
|
||||||
|
@ -112,16 +117,6 @@ public class ParamEntry {
|
||||||
return (((flags & IS_BIG_ENDIAN) == 0) || ((flags & FORCE_LEFT_JUSTIFY) != 0));
|
return (((flags & IS_BIG_ENDIAN) == 0) || ((flags & FORCE_LEFT_JUSTIFY) != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if at least one piece of a join doesn't overlap with another ParamEntry
|
|
||||||
*/
|
|
||||||
public boolean isNonOverlappingJoin() {
|
|
||||||
if (joinrec == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (joinrec.length != groupsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AddressSpace getSpace() {
|
public AddressSpace getSpace() {
|
||||||
return spaceid;
|
return spaceid;
|
||||||
}
|
}
|
||||||
|
@ -130,22 +125,61 @@ public class ParamEntry {
|
||||||
return joinrec;
|
return joinrec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(ParamEntry op2) {
|
/**
|
||||||
if ((type != TYPE_UNKNOWN) && (op2.type != type)) {
|
* Is this ParamEntry, as a memory range, contained by the given memory range.
|
||||||
|
* @param addr is the starting address of the given memory range
|
||||||
|
* @param sz is the number of bytes in the given memory range
|
||||||
|
* @return true if this is contained
|
||||||
|
*/
|
||||||
|
public boolean containedBy(Address addr, int sz) {
|
||||||
|
if (spaceid != addr.getAddressSpace()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (spaceid != op2.spaceid) {
|
if (Long.compareUnsigned(addressbase, addr.getOffset()) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (unsignedCompare(op2.addressbase, addressbase)) {
|
long rangeEnd = addr.getOffset() + sz - 1;
|
||||||
|
long thisEnd = addressbase + size - 1;
|
||||||
|
return (Long.compareUnsigned(thisEnd, rangeEnd) <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this ParamEntry intersect the given range in some way
|
||||||
|
* @param addr is the starting address of the given range
|
||||||
|
* @param sz is the number of bytes in the given range
|
||||||
|
* @return true if there is an intersection
|
||||||
|
*/
|
||||||
|
public boolean intersects(Address addr, int sz) {
|
||||||
|
long rangeend;
|
||||||
|
if (joinrec != null) {
|
||||||
|
rangeend = addr.getOffset() + sz - 1;
|
||||||
|
for (Varnode vn : joinrec) {
|
||||||
|
if (addr.getAddressSpace().getSpaceID() != vn.getSpace()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long vnend = vn.getOffset() + vn.getSize() - 1;
|
||||||
|
if (Long.compareUnsigned(addr.getOffset(), vn.getOffset()) < 0 &&
|
||||||
|
Long.compareUnsigned(rangeend, vnend) < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Long.compareUnsigned(addr.getOffset(), vn.getOffset()) > 0 &&
|
||||||
|
Long.compareUnsigned(rangeend, vnend) > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (spaceid.getSpaceID() != addr.getAddressSpace().getSpaceID()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
long op2end = op2.addressbase + op2.size - 1;
|
rangeend = addr.getOffset() + sz - 1;
|
||||||
long end = addressbase + size - 1;
|
long thisend = addressbase + size - 1;
|
||||||
if (unsignedCompare(end, op2end)) {
|
if (Long.compareUnsigned(addr.getOffset(), addressbase) < 0 &&
|
||||||
|
Long.compareUnsigned(rangeend, thisend) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (alignment != op2.alignment) {
|
if (Long.compareUnsigned(addr.getOffset(), addressbase) > 0 &&
|
||||||
|
Long.compareUnsigned(rangeend, thisend) > 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -177,14 +211,14 @@ public class ParamEntry {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
long startaddr = addr.getOffset();
|
long startaddr = addr.getOffset();
|
||||||
if (unsignedCompare(startaddr, addressbase)) {
|
if (Long.compareUnsigned(startaddr, addressbase) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
long endaddr = startaddr + sz - 1;
|
long endaddr = startaddr + sz - 1;
|
||||||
if (unsignedCompare(endaddr, startaddr)) {
|
if (Long.compareUnsigned(endaddr, startaddr) < 0) {
|
||||||
return -1; // Don't allow wrap around
|
return -1; // Don't allow wrap around
|
||||||
}
|
}
|
||||||
if (unsignedCompare(addressbase + size - 1, endaddr)) {
|
if (Long.compareUnsigned(addressbase + size - 1, endaddr) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
startaddr -= addressbase;
|
startaddr -= addressbase;
|
||||||
|
@ -199,6 +233,27 @@ public class ParamEntry {
|
||||||
return (int) (startaddr % alignment);
|
return (int) (startaddr % alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this ParamEntry contain another entry (as a subpiece)
|
||||||
|
* @param otherEntry is the other entry
|
||||||
|
* @return true if this contains the other entry
|
||||||
|
*/
|
||||||
|
public boolean contains(ParamEntry otherEntry) {
|
||||||
|
if (otherEntry.joinrec != null) {
|
||||||
|
return false; // Assume a join entry cannot be contained
|
||||||
|
}
|
||||||
|
if (joinrec == null) {
|
||||||
|
Address addr = spaceid.getAddress(addressbase);
|
||||||
|
return otherEntry.containedBy(addr, size);
|
||||||
|
}
|
||||||
|
for (Varnode vn : joinrec) {
|
||||||
|
if (otherEntry.containedBy(vn.getAddress(), vn.getSize())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assuming the address is contained in this entry and we -skip- to a certain byte
|
* Assuming the address is contained in this entry and we -skip- to a certain byte
|
||||||
* return the slot associated with that byte
|
* return the slot associated with that byte
|
||||||
|
@ -299,20 +354,6 @@ public class ParamEntry {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int countJoinOverlap(List<ParamEntry> curList) {
|
|
||||||
if (joinrec == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int count = 0;
|
|
||||||
for (Varnode vn : joinrec) {
|
|
||||||
ParamEntry match = findEntryByStorage(curList, vn);
|
|
||||||
if (match != null) {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust the group and groupsize based on the ParamEntrys being overlapped
|
* Adjust the group and groupsize based on the ParamEntrys being overlapped
|
||||||
* @param curList is the current list of ParamEntry
|
* @param curList is the current list of ParamEntry
|
||||||
|
@ -341,11 +382,61 @@ public class ParamEntry {
|
||||||
}
|
}
|
||||||
group = mingrp;
|
group = mingrp;
|
||||||
groupsize = (maxgrp - mingrp);
|
groupsize = (maxgrp - mingrp);
|
||||||
|
flags |= OVERLAPPING;
|
||||||
if (groupsize > joinrec.length) {
|
if (groupsize > joinrec.length) {
|
||||||
throw new XmlParseException("<pentry> join must overlap sequential entries");
|
throw new XmlParseException("<pentry> join must overlap sequential entries");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for overlap with any previous ParamEntry. Reassign group and groupsize to
|
||||||
|
* reflect this overlap.
|
||||||
|
* @param curList is the list of previous ParamEntry
|
||||||
|
* @throws XmlParseException if overlaps do not take the correct form
|
||||||
|
*/
|
||||||
|
private void resolveOverlap(List<ParamEntry> curList) throws XmlParseException {
|
||||||
|
if (joinrec != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int grpsize = 0;
|
||||||
|
int mingrp = 1000;
|
||||||
|
int maxgrp = -1;
|
||||||
|
Address addr = spaceid.getAddress(addressbase);
|
||||||
|
for (ParamEntry entry : curList) {
|
||||||
|
if (entry == this) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!entry.intersects(addr, size)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (contains(entry)) {
|
||||||
|
if (entry.isOverlap()) {
|
||||||
|
continue; // Don't count resources (already counted overlapped pentry)
|
||||||
|
}
|
||||||
|
if (entry.group < mingrp) {
|
||||||
|
mingrp = entry.group;
|
||||||
|
}
|
||||||
|
int max = entry.group + entry.groupsize;
|
||||||
|
if (max > maxgrp) {
|
||||||
|
maxgrp = max;
|
||||||
|
}
|
||||||
|
grpsize += entry.groupsize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new XmlParseException("Illegal overlap of <pentry> in compiler spec");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (grpsize == 0) {
|
||||||
|
return; // No overlaps
|
||||||
|
}
|
||||||
|
if (grpsize != (maxgrp - mingrp)) {
|
||||||
|
throw new XmlParseException("<pentry> must overlap sequential entries");
|
||||||
|
}
|
||||||
|
group = mingrp;
|
||||||
|
groupsize = grpsize;
|
||||||
|
flags |= OVERLAPPING;
|
||||||
|
}
|
||||||
|
|
||||||
public void saveXml(StringBuilder buffer) {
|
public void saveXml(StringBuilder buffer) {
|
||||||
buffer.append("<pentry");
|
buffer.append("<pentry");
|
||||||
SpecXmlUtils.encodeSignedIntegerAttribute(buffer, "minsize", minsize);
|
SpecXmlUtils.encodeSignedIntegerAttribute(buffer, "minsize", minsize);
|
||||||
|
@ -491,6 +582,7 @@ public class ParamEntry {
|
||||||
flags |= IS_GROUPED;
|
flags |= IS_GROUPED;
|
||||||
}
|
}
|
||||||
resolveJoin(curList);
|
resolveJoin(curList);
|
||||||
|
resolveOverlap(curList);
|
||||||
parser.end(el);
|
parser.end(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,16 +613,6 @@ public class ParamEntry {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsigned less-than operation
|
|
||||||
* @param a is the first operand
|
|
||||||
* @param b is the second operand
|
|
||||||
* @return return true is a is less than b, where a and b are interpreted as unsigned integers
|
|
||||||
*/
|
|
||||||
public static boolean unsignedCompare(long a, long b) {
|
|
||||||
return (a + 0x8000000000000000L < b + 0x8000000000000000L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return -1 if (op2,sz2) is not properly contained in (op1,sz1)
|
* Return -1 if (op2,sz2) is not properly contained in (op1,sz1)
|
||||||
* If it is contained, return the endian aware offset of (op2,sz2)
|
* If it is contained, return the endian aware offset of (op2,sz2)
|
||||||
|
@ -551,12 +633,12 @@ public class ParamEntry {
|
||||||
if (spc1 != spc2) {
|
if (spc1 != spc2) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (unsignedCompare(offset2, offset1)) {
|
if (Long.compareUnsigned(offset2, offset1) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
long off1 = offset1 + (sz1 - 1);
|
long off1 = offset1 + (sz1 - 1);
|
||||||
long off2 = offset2 + (sz2 - 1);
|
long off2 = offset2 + (sz2 - 1);
|
||||||
if (unsignedCompare(off1, off2)) {
|
if (Long.compareUnsigned(off1, off2) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (isBigEndian && (!forceleft)) {
|
if (isBigEndian && (!forceleft)) {
|
||||||
|
|
|
@ -317,14 +317,6 @@ public class ParamListStandard implements ParamList {
|
||||||
parseGroup(parser, cspec, pe, numgroup, splitFloat);
|
parseGroup(parser, cspec, pe, numgroup, splitFloat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check that any pentry tags with join storage don't overlap following tags
|
|
||||||
for (ParamEntry curEntry : pe) {
|
|
||||||
if (curEntry.isNonOverlappingJoin()) {
|
|
||||||
if (curEntry.countJoinOverlap(pe) != 1) {
|
|
||||||
throw new XmlParseException("pentry tag must be listed after all its overlaps");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parser.end(mainel);
|
parser.end(mainel);
|
||||||
entry = new ParamEntry[pe.size()];
|
entry = new ParamEntry[pe.size()];
|
||||||
pe.toArray(entry);
|
pe.toArray(entry);
|
||||||
|
|
|
@ -53,14 +53,14 @@
|
||||||
</pentry>
|
</pentry>
|
||||||
</input>
|
</input>
|
||||||
<output>
|
<output>
|
||||||
<pentry minsize="16" maxsize="16" metatype="float">
|
<pentry minsize="4" maxsize="4" metatype="float">
|
||||||
<register name="fq0"/>
|
<register name="fs0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="8" maxsize="8" metatype="float">
|
<pentry minsize="8" maxsize="8" metatype="float">
|
||||||
<register name="fd0"/>
|
<register name="fd0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="4" maxsize="4" metatype="float">
|
<pentry minsize="16" maxsize="16" metatype="float">
|
||||||
<register name="fs0"/>
|
<register name="fq0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="4">
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="o0"/>
|
<register name="o0"/>
|
||||||
|
|
|
@ -30,18 +30,6 @@
|
||||||
<default_proto>
|
<default_proto>
|
||||||
<prototype name="__stdcall" extrapop="0" stackshift="0">
|
<prototype name="__stdcall" extrapop="0" stackshift="0">
|
||||||
<input>
|
<input>
|
||||||
<pentry minsize="16" maxsize="16" metatype="float">
|
|
||||||
<register name="fq0"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="16" maxsize="16" metatype="float">
|
|
||||||
<register name="fq4"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="16" maxsize="16" metatype="float">
|
|
||||||
<register name="fq8"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="16" maxsize="16" metatype="float">
|
|
||||||
<register name="fq12"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="4" maxsize="8" metatype="float">
|
<pentry minsize="4" maxsize="8" metatype="float">
|
||||||
<register name="fd0"/>
|
<register name="fd0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
@ -54,6 +42,18 @@
|
||||||
<pentry minsize="4" maxsize="8" metatype="float">
|
<pentry minsize="4" maxsize="8" metatype="float">
|
||||||
<register name="fd6"/>
|
<register name="fd6"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
<pentry minsize="16" maxsize="16" metatype="float">
|
||||||
|
<register name="fq0"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="16" maxsize="16" metatype="float">
|
||||||
|
<register name="fq4"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="16" maxsize="16" metatype="float">
|
||||||
|
<register name="fq8"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="16" maxsize="16" metatype="float">
|
||||||
|
<register name="fq12"/>
|
||||||
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="8">
|
<pentry minsize="1" maxsize="8">
|
||||||
<register name="o0"/>
|
<register name="o0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
@ -77,14 +77,14 @@
|
||||||
</pentry>
|
</pentry>
|
||||||
</input>
|
</input>
|
||||||
<output>
|
<output>
|
||||||
<pentry minsize="16" maxsize="16" metatype="float">
|
<pentry minsize="4" maxsize="4" metatype="float">
|
||||||
<register name="fq0"/>
|
<register name="fs0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="8" maxsize="8" metatype="float">
|
<pentry minsize="8" maxsize="8" metatype="float">
|
||||||
<register name="fd0"/>
|
<register name="fd0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="4" maxsize="4" metatype="float">
|
<pentry minsize="16" maxsize="16" metatype="float">
|
||||||
<register name="fs0"/>
|
<register name="fq0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="8">
|
<pentry minsize="1" maxsize="8">
|
||||||
<register name="o0"/>
|
<register name="o0"/>
|
||||||
|
|
|
@ -39,30 +39,30 @@
|
||||||
<pentry minsize="1" maxsize="4"> <!-- This is the first non pointer -->
|
<pentry minsize="1" maxsize="4"> <!-- This is the first non pointer -->
|
||||||
<register name="a4"/>
|
<register name="a4"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="4"> <!-- This is the first non pointer -->
|
|
||||||
<register name="d4"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="5" maxsize="8"> <!-- This is the first >4 byte non pointer -->
|
|
||||||
<register name="e4"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="1" maxsize="4">
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="a5"/>
|
<register name="a5"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4">
|
||||||
|
<register name="a6"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4">
|
||||||
|
<register name="a7"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4"> <!-- This is the first non pointer -->
|
||||||
|
<register name="d4"/>
|
||||||
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="4">
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="d5"/>
|
<register name="d5"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="4">
|
|
||||||
<register name="a6"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="1" maxsize="4">
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="d6"/>
|
<register name="d6"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="4">
|
|
||||||
<register name="a7"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="1" maxsize="4">
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="d7"/>
|
<register name="d7"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
<pentry minsize="5" maxsize="8"> <!-- This is the first >4 byte non pointer -->
|
||||||
|
<register name="e4"/>
|
||||||
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="500" align="4">
|
<pentry minsize="1" maxsize="500" align="4">
|
||||||
<addr offset="16" space="ram"/>
|
<addr offset="16" space="ram"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
@ -112,15 +112,12 @@
|
||||||
<pentry minsize="1" maxsize="4"> <!-- This is the first non pointer -->
|
<pentry minsize="1" maxsize="4"> <!-- This is the first non pointer -->
|
||||||
<register name="d4"/>
|
<register name="d4"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="5" maxsize="8"> <!-- This is the first >4 byte non pointer -->
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="e4"/>
|
<register name="d5"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="4">
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="a5"/>
|
<register name="a5"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="4">
|
|
||||||
<register name="d5"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="1" maxsize="4">
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="a6"/>
|
<register name="a6"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
@ -133,6 +130,9 @@
|
||||||
<pentry minsize="1" maxsize="4">
|
<pentry minsize="1" maxsize="4">
|
||||||
<register name="d7"/>
|
<register name="d7"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
<pentry minsize="5" maxsize="8"> <!-- This is the first >4 byte non pointer -->
|
||||||
|
<register name="e4"/>
|
||||||
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="500" align="4">
|
<pentry minsize="1" maxsize="500" align="4">
|
||||||
<addr offset="16" space="ram"/>
|
<addr offset="16" space="ram"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue