GP-2213_emteere support for 24-bit spaces, byte addressed code space, hex importer fixes, AVR8 relocations

This commit is contained in:
emteere 2022-07-11 08:06:06 -04:00
parent cd7599e3b9
commit b34f43e685
13 changed files with 532 additions and 102 deletions

View File

@ -2999,14 +2999,14 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
if (type != ElfSectionHeaderConstants.SHT_NOBITS &&
(fileOffset < 0 || fileOffset >= fileBytes.getSize())) {
log("Skipping section [" + elfSectionToLoad.getNameAsString() +
"] with invalid file offset");
"] with invalid file offset 0x" + Long.toHexString(fileOffset));
continue;
}
long size = elfSectionToLoad.getSize();
if (size <= 0 ||
(type != ElfSectionHeaderConstants.SHT_NOBITS && size >= fileBytes.getSize())) {
log("Skipping section [" + elfSectionToLoad.getNameAsString() +
"] with invalid size");
"] with invalid size 0x" + Long.toHexString(size));
continue;
}
processSectionHeader(elfSectionToLoad, relocatableImageBaseProvider);

View File

@ -230,7 +230,7 @@ public class IntelHexLoader extends AbstractProgramLoader {
}
String msg = memImage.createMemory(getName(), provider.getName(),
isOverlay ? blockName : null, isOverlay, program, monitor);
blockName, isOverlay, program, monitor);
if (msg.length() > 0) {
log.appendMsg(msg);

View File

@ -96,6 +96,10 @@ class IntelHexMemImage {
}
break;
case IntelHexRecord.END_OF_FILE_RECORD_TYPE:
// if hit EOF record, everything after goes into an OTHER space
// TODO maybe this should go into the data space?
space = AddressSpace.OTHER_SPACE;
base = space.getAddress(0);
// nothing to do, we're at the end (or should we ensure further parses fail?)
// log(line, "end of file");
break;
@ -180,7 +184,6 @@ class IntelHexMemImage {
MessageLog log = new MessageLog();
//this code is required to allow hex lines to not appear
//in address order...
int count = 0;
AddressSetPartitioner partitioner = new AddressSetPartitioner(set, rangeMap, partitions);
HashMap<AddressRange, byte[]> myRangeMap =
new HashMap<AddressRange, byte[]>(partitioner.getPartionedRangeMap());
@ -203,14 +206,14 @@ class IntelHexMemImage {
System.arraycopy(rangeBytes, 0, data, pos, rangeBytes.length);
for (int jj = 0; jj < rangeBytes.length; ++jj) {
if (filled[pos + jj]) {
System.err.println("OVERWRITE!");
Msg.error(this, "Hex format Overwrite of bytes at " + range.getMinAddress().add(pos+jj));
}
filled[pos + jj] = true;
}
myRangeMap.remove(range);
}
String name = blockName == null ? base.getAddressSpace().getName() : blockName;
String name = blockName == null ? blockRange.getMinAddress().getAddressSpace().getName() : blockName;
MemoryBlockUtils.createInitializedBlock(program, isOverlay, name,
blockRange.getMinAddress(), new ByteArrayInputStream(data), data.length,
"Generated by " + creator, progFile, true, !isOverlay, !isOverlay, log, monitor);

View File

@ -20,6 +20,12 @@
<range space="mem" first="0x60" last="0xff"/>
</volatile>
<context_data>
<tracked_set space="code">
<set name="R1" val="0"/>
</tracked_set>
</context_data>
<default_symbols>
<symbol name="RESET" address="code:0x0000" entry="true"/>
@ -408,7 +414,8 @@
<default_memory_blocks>
<memory_block name="regalias" start_address="mem:0x00" length="0x20" initialized="false"/>
<memory_block name="iospace" start_address="mem:0x20" length="0x1e0" initialized="false"/>
<memory_block name="data" start_address="mem:0x200" length="0x2000" initialized="false"/>
<memory_block name="sram" start_address="mem:0x200" length="0x4000" initialized="false"/>
<memory_block name="codebyte" start_address="codebyte:0x0" length="0x40000" byte_mapped_address="code:0x0"/>
</default_memory_blocks>

View File

@ -6,7 +6,7 @@
endian="little"
size="16"
variant="default"
version="1.2"
version="1.3"
slafile="avr8.sla"
processorspec="avr8.pspec"
manualindexfile="../manuals/AVR8.idx"
@ -23,7 +23,7 @@
endian="little"
size="16"
variant="extended"
version="1.3"
version="1.4"
slafile="avr8e.sla"
processorspec="avr8.pspec"
manualindexfile="../manuals/AVR8.idx"
@ -38,7 +38,7 @@
endian="little"
size="24"
variant="atmega256"
version="1.3"
version="1.4"
slafile="avr8eind.sla"
processorspec="atmega256.pspec"
manualindexfile="../manuals/AVR8.idx"
@ -53,7 +53,7 @@
endian="little"
size="24"
variant="Xmega"
version="1.3"
version="1.4"
slafile="avr8xmega.sla"
processorspec="avr8xmega.pspec"
id="avr8:LE:24:xmega">

View File

@ -24,6 +24,12 @@
<range space="mem" first="0x60" last="0xff"/>
</volatile>
<context_data>
<tracked_set space="code">
<set name="R1" val="0"/>
</tracked_set>
</context_data>
<default_symbols>
<symbol name="Reset" address="code:0x0" entry="true"/>
@ -162,6 +168,7 @@
<memory_block name="regalias" start_address="mem:0x00" length="0x20" initialized="false"/>
<memory_block name="iospace" start_address="mem:0x20" length="0xd0" initialized="false"/>
<memory_block name="mem" start_address="mem:0x100" length="0xf00" initialized="false"/>
<memory_block name="codebyte" start_address="codebyte:0x0" length="0x10000" byte_mapped_address="code:0x0"/>
</default_memory_blocks>

View File

@ -31,10 +31,14 @@ define alignment=2;
# decompiler. None-the-less, other than when loading the binary into
# Ghidra, it's still preferable to see the name of IO locations used,
# rather than code addresses, so leave mem space as the default.
define space code type=ram_space size=$(PCBYTESIZE) wordsize=2 default;
define space register type=register_space size=2;
define space mem type=ram_space size=2 wordsize=1;
# this is a byte address space that should be overlayed on top of the code space
define space codebyte type=ram_space size=$(PCBYTESIZE) wordsize=1;
# Using decimal rather than hex to match specs
# General registers start at 0 in the iospace for earlier avr8 processors
# In the Xmega line, they are not accessible in mem, and are in a register space
@ -53,8 +57,13 @@ define $(REGISTER_SPACE) offset=0 size=2 [
X Y Z
];
define $(REGISTER_SPACE) offset=0x10 size=4 [
R19R18R17R16 R23R22R21R20
define $(REGISTER_SPACE) offset=18 size=8 [
R25R24R23R22R21R20R19R18
];
define $(REGISTER_SPACE) offset=0 size=8 [
R7R6R5R4R3R2R1R0
R15R14R13R12R11R10R9R8
];
# Technically, the stack pointer is in the i/o space so should be addressable with the
@ -143,6 +152,7 @@ define token opword (16)
ophi2 = (14,15)
opbit13 = (13,13)
opbit12 = (12,12)
opbit10 = (10,10)
opbit9 = ( 9, 9)
opbit8 = ( 8, 8)
opbit7 = ( 7, 7)
@ -162,6 +172,7 @@ define token opword (16)
op4to6 = ( 4, 6)
op4to6_flag = ( 4, 6)
op6to7 = ( 6, 7)
op8to10 = ( 8,10)
op9to10 = ( 9,10)
op10to11 = (10,11)
RdHi = ( 4, 7)
@ -325,45 +336,28 @@ op1RrPair: op1RrPairLow is op1RrPairSel=0 & op1RrPairLow { tmp:2 = op1RrPairLow
# manipulates the stack pointer it's important to get this correct.
@if PCBYTESIZE == "2"
macro pushPC(val) {
local valb:1 = val(0);
*[mem]:1 SP = valb;
SP = SP - 1;
valb = val(1);
*[mem]:1 SP = valb;
SP = SP - 1;
*[mem]:2 SP = val;
SP = SP - 1;
}
macro popPC(val) {
local valb:1 = 0;
SP = SP + 1;
val = *[mem]:2 SP;
SP = SP + 1;
val = *[mem]:1 SP;
SP = SP + 1;
valb = *[mem]:1 SP;
val = (val << 8) + zext(valb);
}
@else # PCBYTESIZE == 3
macro pushPC(val) {
local valb:1 = val(0);
*[mem]:1 SP = valb;
SP = SP - 1;
valb = val(1);
*[mem]:1 SP = valb;
SP = SP - 1;
valb = val(2);
*[mem]:1 SP = valb;
SP = SP - 2;
*[mem]:3 SP = val;
SP = SP - 1;
}
macro popPC(val) {
SP = SP + 1;
val = *[mem]:1 SP;
SP = SP + 1;
local valb = *[mem]:1 SP;
val = (val << 8) + zext(valb);
SP = SP + 1;
valb = *[mem]:1 SP;
val = (val << 8) + zext(valb);
SP = SP + 1;
val = *[mem]:3 SP;
SP = SP + 2;
}
@endif
@ -499,7 +493,7 @@ K6: val is oplow4 & op6to7 [ val = (op6to7 << 4) | oplow4; ] { tmp:1 = val; e
# K7 is used by lds
K7addr: val is oplow4 & op9to10 & opbit8 [ val = ((1 ^ opbit8) << 7) | (opbit8 << 6) | (op9to10 << 4) | oplow4; ] {
tmp:1 = val; export tmp;
export *[mem]:1 val;
}
# Join against various spaces for dataspace...
@ -740,10 +734,10 @@ define pcodeop decrypt;
:des op4to7 is phase=1 & ophi8=0x94 & oplow4=0xb & op4to7 {
val:1 = op4to7;
if (Hflg) goto <enc>;
decrypt(val);
R15R14R13R12R11R10R9R8 = decrypt(R7R6R5R4R3R2R1R0, val);
goto inst_next;
<enc>
encrypt(val);
R15R14R13R12R11R10R9R8 = encrypt(R7R6R5R4R3R2R1R0, val);
}
@if HASEIND == "1"
@ -764,23 +758,21 @@ define pcodeop decrypt;
@if PCBYTESIZE == "3"
:elpm is phase=1 & ophi16=0x95d8 {
ptr:3 = zext(Z) | (zext(RAMPZ) << 16);
tmp:2 = *[code]:2 (ptr >> 1);
val:2 = (tmp >> (8 * (Z & 0x1)));
R0 = val:1;
local falseRead:1 = *[code]:2 (ptr >> 1);
R0 = *[codebyte]:1 ptr;
}
:elpm RdFull, Z is phase=1 & ophi7=0x48 & oplow4=0x6 & RdFull & Z {
ptr:3 = zext(Z) | (zext(RAMPZ) << 16);
tmp:2 = *[code]:2 (ptr >> 1);
val:2 = (tmp >> (8 * (Z & 0x1)));
RdFull = val:1;
local falseRead:1 = *[code]:1 (ptr >> 1);
RdFull = *[codebyte]:1 ptr;
}
ElpmPlus: Z^"+" is Z {}
:elpm RdFull, ElpmPlus is phase=1 & ophi7=0x48 & oplow4=0x7 & RdFull & ElpmPlus {
ptr:3 = zext(Z) | (zext(RAMPZ) << 16);
tmp:2 = *[code]:2 (ptr >> 1);
val:2 = (tmp >> (8 * (Z & 0x1)));
RdFull = val:1;
local falseRead:1 = *[code]:1 (ptr >> 1);
RdFull = *[codebyte]:1 ptr;
ptr = ptr + 1;
Z = ptr:2;
RAMPZ = ptr[16,8];
@ -862,6 +854,7 @@ ElpmPlus: Z^"+" is Z {}
RdFull = *[mem]:1 tmp;
}
# ld Rd,Y; ld Rd,Z
# Special case of ldd +q below - will conflict with -i sleigh compile
:ld RdFull,RstPtr is phase=1 & ophi7=0x40 & oplow3=0x0 & RdFull & RstPtr {
tmp:2 = RstPtr;
RdFull = *[mem]:1 tmp;
@ -883,9 +876,9 @@ LdPredec: "-"^RstPtr is RstPtr { RstPtr = RstPtr - 0x01; export RstPtr; }
# ldd Rd,Y+q
# ldd Rd,Z+q
LddYq: Rstq^"+"^q6 is Rstq & q6 { local ptr = Rstq + zext(q6); export ptr; }
:ldd RdFull,LddYq is phase=1 & ophi2=0x2 & opbit12=0 & opbit9=0 & LddYq & RdFull {
RdFull = *[mem]:1 LddYq;
LddYZq: Rstq^"+"^q6 is phase=1 & Rstq & q6 { local ptr = Rstq + zext(q6); export ptr; }
:ldd RdFull,LddYZq is phase=1 & ophi2=0x2 & opbit12=0 & opbit9=0 & opbit3 & LddYZq & RdFull {
RdFull = *[mem]:1 LddYZq;
}
# Rd,K
@ -914,32 +907,28 @@ LddYq: Rstq^"+"^q6 is Rstq & q6 { local ptr = Rstq + zext(q6); export ptr; }
@endif
# lds Rd,k Seem to get some problems here... but 16-bit instruction isn't available on all atmega64.
# Furthermore, it will sometimes conflict with ldd Z+q for q=0x2_
#:lds RdHi,A7Ioaddr is ophi5=0x14 & RdHi & A7Ioaddr {
# todo(); # Not currently implemented
# RdHi = A7Ioaddr;
#}
# TODO: lpm semantic behavior needs verification !
:lds RdHi,K7addr is phase=1 & ophi5=0x14 & RdHi & K7addr {
RdHi = K7addr;
}
# lpm R0
:lpm R0 is phase=1 & ophi16=0x95c8 & R0 {
ptr:$(PCBYTESIZE) = zext(Z);
tmp:$(PCBYTESIZE) = *[code]:$(PCBYTESIZE) (ptr >> 1);
val:$(PCBYTESIZE) = (tmp >> (8 * (Z & 0x1)));
R0 = val:1;
local falseRead:1 = *[code]:1 (ptr >> 1);
R0 = *[codebyte]:$(PCBYTESIZE) ptr;
}
# lpm Rd,Z
:lpm RdFull,Z is phase=1 & ophi7=0x48 & op1to3=0x2 & RdFull & Z & opbit0=0 {
ptr:$(PCBYTESIZE) = zext(Z);
tmp:$(PCBYTESIZE) = *[code]:$(PCBYTESIZE) (ptr >> 1);
val:$(PCBYTESIZE) = (tmp >> (8 * (Z & 0x1)));
RdFull = val:1;
local falseRead:1 = *[code]:1 (ptr >> 1);
RdFull = *[codebyte]:$(PCBYTESIZE) ptr;
}
# lpm Rd,Z+
LpmPlus: Z^"+" is Z {}
:lpm RdFull,LpmPlus is phase=1 & ophi7=0x48 & op1to3=0x2 & RdFull & LpmPlus & opbit0=1 {
ptr:$(PCBYTESIZE) = zext(Z);
tmp:$(PCBYTESIZE) = *[code]:$(PCBYTESIZE) (ptr >> 1);
val:$(PCBYTESIZE) = (tmp >> (8 * (Z & 0x1)));
RdFull = val:1;
local falseRead:1 = *[code]:1 (ptr >> 1);
RdFull = *[codebyte]:$(PCBYTESIZE) ptr;
Z = Z + 1;
}
# lsl - just an assembly mnemonic for add
@ -1118,14 +1107,16 @@ define pcodeop store_program_mem; # make this stand out.
:spm Z is phase=1 & ophi16=0x95e8 & Z {
ptr:$(PCBYTESIZE) = zext(Z) << 1;
*[code]:$(PCBYTESIZE) ptr = R1R0;
local falseWrite:1 = *[code]:1 (ptr >> 1);
*[codebyte]:$(PCBYTESIZE) ptr = R1R0;
store_program_mem();
}
SpmPlus: Z^"+" is Z {}
:spm SpmPlus is phase=1 & ophi16=0x95f8 & SpmPlus {
ptr:$(PCBYTESIZE) = zext(Z) << 1;
*[code]:$(PCBYTESIZE) ptr = R1R0;
local falseWrite:1 = *[code]:1 (ptr >> 1);
*[codebyte]:$(PCBYTESIZE) ptr = R1R0;
Z = Z + 1;
store_program_mem();
}
@ -1154,11 +1145,11 @@ StPredec: "-"^RstPtr is RstPtr { RstPtr = RstPtr - 0x01; export RstPtr; }
*[mem]:1 tmp = RdFull;
}
# std Rd,Y+q; std Rd,Z+q
StdYq: Rstq^"+"^q6 is Rstq & q6 { local ptr = Rstq + zext(q6); export ptr; }
:std StdYq, RdFull is phase=1 & ophi2=0x2 & opbit12=0 & opbit9=1 & RdFull & StdYq {
*[mem]:1 StdYq = RdFull;
# std Rd,Y+q
# std Rd,Z+q
StdYZq: Rstq^"+"^q6 is Rstq & q6 { local ptr = Rstq + zext(q6); export ptr; }
:std StdYZq, RdFull is phase=1 & ophi2=0x2 & opbit12=0 & opbit9=1 & RdFull & opbit3 & StdYZq {
*[mem]:1 StdYZq = RdFull;
}
:sts next16memPtrVal1,RdFull is phase=1 & ophi7=0x49 & oplow4=0 & RdFull; next16memPtrVal1 {
@ -1173,7 +1164,9 @@ StdYq: Rstq^"+"^q6 is Rstq & q6 { local ptr = Rstq + zext(q6); export ptr; }
@endif
# see manual for computation of address for 16-bit STS
:sts RdHi is phase=1 & ophi5=0x15 & RdHi { todo(); }
:sts K7addr, RdHi is phase=1 & ophi5=0x15 & RdHi & K7addr {
K7addr = RdHi;
}
:sub RdFull,RrFull is phase=1 & ophi6=0x6 & RdFull & RrFull {
doSubtract(RdFull,RrFull,RdFull);
}

View File

@ -32,6 +32,7 @@
<global>
<range space="code"/>
<range space="mem"/>
<range space="codebyte"/>
</global>
<stackpointer register="SP" space="mem" growth="negative"/>
@ -39,25 +40,18 @@
<default_proto>
<prototype name="__stdcall" extrapop="3" stackshift="3" strategy="register">
<input>
<!-- Stack used for vararg parameters only -->
<pentry minsize="1" maxsize="2">
<pentry minsize="1" maxsize="2">
<register name="W"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="R23R22"/>
</pentry>
<pentry minsize="3" maxsize="4">
<addr space="join" piece1="W" piece2="R23R22"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="R21R20"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="R19R18"/>
</pentry>
<pentry minsize="3" maxsize="4">
<addr space="join" piece1="R21R20" piece2="R19R18"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="R17R16"/>
</pentry>
@ -73,6 +67,14 @@
<pentry minsize="1" maxsize="2">
<register name="R9R8"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="Z"/>
</pentry>
<!-- set to 20 on purpose, so that large values don't get assigned to stack -->
<!-- They get allocated across register pairs, but layout algorithm too simple -->
<pentry minsize="24" maxsize="500" align="1">
<addr offset="20" space="stack"/>
</pentry>
</input>
<output>
<pentry minsize="1" maxsize="2">
@ -81,6 +83,9 @@
<pentry minsize="3" maxsize="4">
<addr space="join" piece1="W" piece2="R23R22"/>
</pentry>
<pentry minsize="5" maxsize="8">
<addr space="join" piece1="W" piece2="R23R22" piece3="R21R20" piece4="R19R18"/>
</pentry>
</output>
<unaffected>
<register name="SP"/>
@ -103,6 +108,21 @@
<register name="R17"/>
<register name="Y"/>
</unaffected>
<killedbycall>
<register name="R0"/>
<register name="R18"/>
<register name="R19"/>
<register name="R20"/>
<register name="R21"/>
<register name="R22"/>
<register name="R23"/>
<register name="Wlo"/>
<register name="Whi"/>
<register name="Xlo"/>
<register name="Xhi"/>
<register name="Zlo"/>
<register name="Zhi"/>
</killedbycall>
</prototype>
</default_proto>

View File

@ -31,13 +31,14 @@
<global>
<range space="code"/>
<range space="codebyte"/>
<range space="mem"/>
</global>
<stackpointer register="SP" space="mem" growth="negative"/>
<default_proto>
<prototype name="__stdcall" extrapop="2" stackshift="2" strategy="register">
<prototype name="__stdcall" extrapop="" stackshift="2" strategy="register">
<input>
<pentry minsize="1" maxsize="2">
<register name="W"/>
@ -45,18 +46,12 @@
<pentry minsize="1" maxsize="2">
<register name="R23R22"/>
</pentry>
<pentry minsize="3" maxsize="4">
<addr space="join" piece1="W" piece2="R23R22"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="R21R20"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="R19R18"/>
</pentry>
<pentry minsize="3" maxsize="4">
<addr space="join" piece1="R21R20" piece2="R19R18"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="R17R16"/>
</pentry>
@ -72,6 +67,14 @@
<pentry minsize="1" maxsize="2">
<register name="R9R8"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="Z"/>
</pentry>
<!-- set to 20 on purpose, so that large values don't get assigned to stack -->
<!-- They get allocated across register pairs, but layout algorithm too simple -->
<pentry minsize="24" maxsize="500" align="1">
<addr offset="20" space="stack"/>
</pentry>
</input>
<output>
<pentry minsize="1" maxsize="2">
@ -80,6 +83,9 @@
<pentry minsize="3" maxsize="4">
<addr space="join" piece1="W" piece2="R23R22"/>
</pentry>
<pentry minsize="5" maxsize="8">
<addr space="join" piece1="W" piece2="R23R22" piece3="R21R20" piece4="R19R18"/>
</pentry>
</output>
<unaffected>
<register name="SP"/>
@ -102,15 +108,30 @@
<register name="R17"/>
<register name="Y"/>
</unaffected>
<killedbycall>
<register name="R0"/>
<register name="R18"/>
<register name="R19"/>
<register name="R20"/>
<register name="R21"/>
<register name="R22"/>
<register name="R23"/>
<register name="Wlo"/>
<register name="Whi"/>
<register name="Xlo"/>
<register name="Xhi"/>
<register name="Zlo"/>
<register name="Zhi"/>
</killedbycall>
</prototype>
</default_proto>
<prototype name="__stackcall" extrapop="3" stackshift="3" strategy="register">
<input>
<pentry minsize="1" maxsize="500" align="1">
<addr offset="1" space="stack"/>
</pentry>
</input>
<pentry minsize="1" maxsize="500" align="1">
<addr offset="3" space="stack"/>
</pentry>
</input>
<output>
<pentry minsize="1" maxsize="2">
<register name="W"/>

View File

@ -5,6 +5,7 @@
<compiler_spec>
<global>
<range space="code"/>
<range space="codebyte"/>
<range space="mem" first="40" last="0xffff"/>
<!-- <range space="iospace"/> -->
</global>
@ -15,18 +16,18 @@
<prototype name="__stdcall" extrapop="0" stackshift="0" strategy="register">
<input>
<pentry minsize="1" maxsize="4">
<register name="R19R18R17R16"/>
<addr space="join" piece1="R19R18" piece2="R17R16"/>
</pentry>
<pentry minsize="1" maxsize="2">
<register name="R23R22R21R20"/>
<pentry minsize="1" maxsize="4">
<addr space="join" piece1="R23R22" piece2="R21R20"/>
</pentry>
<pentry minsize="1" maxsize="500" align="1">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output>
<pentry minsize="1" maxsize="2">
<register name="R19R18R17R16"/>
<pentry minsize="1" maxsize="4">
<addr space="join" piece1="R19R18" piece2="R17R16"/>
</pentry>
</output>
<unaffected>

View File

@ -7,6 +7,7 @@
<compiler_spec>
<global>
<range space="code"/>
<range space="codebyte"/>
<range space="mem" first="40" last="0xffff"/>
</global>
<!-- SP is used for the code stack. Y is used for the data stack -->

View File

@ -20,6 +20,12 @@
<range space="mem" first="0x40" last="0xfff"/>
</volatile>
<context_data>
<tracked_set space="code">
<set name="R1" val="0"/>
</tracked_set>
</context_data>
<default_symbols>
@ -1476,6 +1482,8 @@
<default_memory_blocks>
<memory_block name="iospace" start_address="mem:0x00" length="0x1000" initialized="false"/>
<memory_block name="eeprom" start_address="mem:0x1000" length="0x1000" initialized="false"/>
<memory_block name="sram" start_address="mem:0x2000" length="0x4000" initialized="false"/>
<memory_block name="codebyte" start_address="codebyte:0x0" length="0x40000" byte_mapped_address="code:0x0"/>
</default_memory_blocks>

View File

@ -0,0 +1,369 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf.relocation;
import ghidra.app.util.bin.format.elf.AVR8_ElfRelocationConstants;
import ghidra.app.util.bin.format.elf.ElfConstants;
import ghidra.app.util.bin.format.elf.ElfHeader;
import ghidra.app.util.bin.format.elf.ElfRelocation;
import ghidra.app.util.bin.format.elf.ElfSymbol;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.util.exception.NotFoundException;
public class AVR8_ElfRelocationHandler extends ElfRelocationHandler {
@Override
public boolean canRelocate(ElfHeader elf) {
return elf.e_machine() == ElfConstants.EM_AVR;
}
@Override
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
Address relocationAddress) throws MemoryAccessException, NotFoundException {
Program program = elfRelocationContext.getProgram();
Memory memory = program.getMemory();
int type = relocation.getType();
int symbolIndex = relocation.getSymbolIndex();
long addend = relocation.getAddend(); // will be 0 for REL case
ElfHeader elf = elfRelocationContext.getElfHeader();
if ((symbolIndex == 0) && (elf.e_machine() == ElfConstants.EM_AVR)) {
// System.out.println("ZERO_SYMBOL_TYPE = " + type + ", Offset = " + offset + ",
// Addend = " + addend);
}
else if (symbolIndex == 0) {
return;
}
// WARNING: offset is in bytes
// be careful, word address potentially with byte indexes
long offset = relocationAddress.getOffset();
ElfSymbol sym = elfRelocationContext.getSymbol(symbolIndex);
// WARNING: symbolValue here is not in bytes.
// it is an addressable word offset for the symbols address space
long symbolValue = elfRelocationContext.getSymbolValue(sym);
String symbolName = sym.getNameAsString();
int oldValue = memory.getShort(relocationAddress);
if (elf.e_machine() != ElfConstants.EM_AVR) {
return;
}
int newValue = 0;
switch (type) {
case AVR8_ElfRelocationConstants.R_AVR_NONE:
break;
case AVR8_ElfRelocationConstants.R_AVR_32:
newValue = (((int) symbolValue + (int) addend) & 0xffffffff);
memory.setInt(relocationAddress, newValue);
break;
case AVR8_ElfRelocationConstants.R_AVR_7_PCREL:
newValue = (int) ((symbolValue * 2 + (int) addend - offset));
newValue -= 2; // branch PC is offset+2
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
if (newValue > ((1 << 7) - 1) || (newValue < -(1 << 7))) {
markAsError(program, relocationAddress, type, symbolName, "relocation overflow",
elfRelocationContext.getLog());
return;
}
newValue = (oldValue & 0xfc07) | (((newValue >> 1) << 3) & 0x3f8);
memory.setShort(relocationAddress, (short) newValue);
break;
case AVR8_ElfRelocationConstants.R_AVR_13_PCREL:
newValue = (int) ((symbolValue * 2 + (int) addend - offset));
newValue -= 2; // branch PC is offset+2
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
newValue >>= 1;
if (newValue < -2048 || newValue > 2047) {
markAsWarning(program, relocationAddress, symbolName, symbolName, symbolIndex,
"possible relocation error", elfRelocationContext.getLog());
}
newValue = (oldValue & 0xf000) | (newValue & 0xfff);
memory.setShort(relocationAddress, (short) newValue);
break;
case AVR8_ElfRelocationConstants.R_AVR_16:
newValue = ((int) symbolValue + (int) addend);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_16_PM:
newValue = (((int) symbolValue * 2 + (int) addend));
newValue >>= 1;
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_LO8_LDI:
newValue = (((int) symbolValue + (int) addend));
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_HI8_LDI:
newValue = (((int) symbolValue + (int) addend));
newValue = (newValue >> 8) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_HH8_LDI:
newValue = (((int) symbolValue + (int) addend));
newValue = (newValue >> 16) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_LO8_LDI_NEG:
newValue = (((int) symbolValue + (int) addend));
newValue = -newValue;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_HI8_LDI_NEG:
newValue = (((int) symbolValue + (int) addend));
newValue = -newValue;
newValue = (newValue >> 8) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_HH8_LDI_NEG:
newValue = (((int) symbolValue + (int) addend));
newValue = -newValue;
newValue = (newValue >> 16) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_LO8_LDI_PM:
newValue = (((int) symbolValue * 2 + (int) addend));
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
newValue >>= 1;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_HI8_LDI_PM:
newValue = (((int) symbolValue * 2 + (int) addend));
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
newValue >>= 1;
newValue = (newValue >> 8) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_HH8_LDI_PM:
newValue = (((int) symbolValue * 2 + (int) addend));
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
newValue >>= 1;
newValue = (newValue >> 16) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_LO8_LDI_PM_NEG:
newValue = (((int) symbolValue * 2 + (int) addend));
newValue = -newValue;
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
newValue >>= 1;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_HI8_LDI_PM_NEG:
newValue = (((int) symbolValue * 2 + (int) addend));
newValue = -newValue;
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
newValue >>= 1;
newValue = (newValue >> 8) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_HH8_LDI_PM_NEG:
newValue = (((int) symbolValue * 2 + (int) addend));
newValue = -newValue;
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
newValue >>= 1;
newValue = (newValue >> 16) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_CALL:
newValue = (int) symbolValue * 2 + (int) addend;
if ((newValue & 1) == 1) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
return;
}
newValue >>= 1;
int hiValue =
oldValue | ((newValue & 0x10000) | ((newValue << 3) & 0x1f00000)) >> 16;
memory.setShort(relocationAddress, (short) (hiValue & 0xffff));
memory.setShort(relocationAddress.add(2), (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_LDI: /* data/eeprom */
newValue = (((int) symbolValue + (int) addend));
if ((newValue & 0xffff) > 255) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
}
newValue = (newValue >> 8) & 0xff;
newValue = (oldValue & 0xf0f0) | (newValue & 0xf) | ((newValue << 4) & 0xf00);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_6: /* data/eeprom **/
newValue = (((int) symbolValue + (int) addend));
if (((newValue & 0xffff) > 63) || (newValue < 0)) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
}
newValue = (oldValue & 0xd3f8) | (newValue & 7) | ((newValue & (3 << 3)) << 7) |
((newValue & (1 << 5)) << 8);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_6_ADIW:
newValue = (((int) symbolValue + (int) addend));
if (((newValue & 0xffff) > 63) || (newValue < 0)) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
}
newValue = (oldValue & 0xff30) | (newValue & 0xF) | ((newValue & 0x30) << 2);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_DIFF8:
case AVR8_ElfRelocationConstants.R_AVR_DIFF16:
case AVR8_ElfRelocationConstants.R_AVR_DIFF32:
// nothing to do
break;
case AVR8_ElfRelocationConstants.R_AVR_LDS_STS_16:
newValue = (((int) symbolValue + (int) addend));
if (((newValue & 0xffff) < 0x40) || (newValue & 0xFFFF) > 0xbf) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
}
newValue = newValue & 0x7f;
newValue = (oldValue & 0x0f) | ((newValue & 0x30) << 5) | ((newValue & 0x40) << 2);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_PORT6:
newValue = (((int) symbolValue + (int) addend));
if ((newValue & 0xffff) > 0x3f) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
}
newValue = (oldValue & 0xf9f0) | ((newValue & 0x30) << 5) | (newValue & 0x0f);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_PORT5:
newValue = (((int) symbolValue + (int) addend));
if ((newValue & 0xffff) > 0x1f) {
markAsError(program, relocationAddress, type, symbolName,
"relocation out of range", elfRelocationContext.getLog());
}
newValue = (oldValue & 0xff07) | ((newValue & 0x1f) << 3);
memory.setShort(relocationAddress, (short) (newValue & 0xffff));
break;
case AVR8_ElfRelocationConstants.R_AVR_MS8_LDI:
case AVR8_ElfRelocationConstants.R_AVR_MS8_LDI_NEG:
case AVR8_ElfRelocationConstants.R_AVR_LO8_LDI_GS:
case AVR8_ElfRelocationConstants.R_AVR_HI8_LDI_GS:
case AVR8_ElfRelocationConstants.R_AVR_8:
case AVR8_ElfRelocationConstants.R_AVR_8_LO8:
case AVR8_ElfRelocationConstants.R_AVR_8_HI8:
case AVR8_ElfRelocationConstants.R_AVR_8_HLO8:
default:
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
elfRelocationContext.getLog());
break;
}
}
}