diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java index 8d08e42f6a..0a730fd8bf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java @@ -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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexLoader.java index 7d67f4833d..5a5a641451 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexLoader.java @@ -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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexMemImage.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexMemImage.java index 36459b6b8b..01f11703ea 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexMemImage.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexMemImage.java @@ -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 myRangeMap = new HashMap(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); diff --git a/Ghidra/Processors/Atmel/data/languages/atmega256.pspec b/Ghidra/Processors/Atmel/data/languages/atmega256.pspec index f77f889310..df70dff4b8 100644 --- a/Ghidra/Processors/Atmel/data/languages/atmega256.pspec +++ b/Ghidra/Processors/Atmel/data/languages/atmega256.pspec @@ -20,6 +20,12 @@ + + + + + + @@ -408,7 +414,8 @@ - + + diff --git a/Ghidra/Processors/Atmel/data/languages/avr8.ldefs b/Ghidra/Processors/Atmel/data/languages/avr8.ldefs index eeb1463cc7..e920a37651 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8.ldefs +++ b/Ghidra/Processors/Atmel/data/languages/avr8.ldefs @@ -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"> diff --git a/Ghidra/Processors/Atmel/data/languages/avr8.pspec b/Ghidra/Processors/Atmel/data/languages/avr8.pspec index 01cb20db50..2903e033a5 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8.pspec +++ b/Ghidra/Processors/Atmel/data/languages/avr8.pspec @@ -24,6 +24,12 @@ + + + + + + @@ -162,6 +168,7 @@ + diff --git a/Ghidra/Processors/Atmel/data/languages/avr8.sinc b/Ghidra/Processors/Atmel/data/languages/avr8.sinc index 63a6365ce4..521bd64bd6 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8.sinc +++ b/Ghidra/Processors/Atmel/data/languages/avr8.sinc @@ -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 ; - decrypt(val); + R15R14R13R12R11R10R9R8 = decrypt(R7R6R5R4R3R2R1R0, val); goto inst_next; - 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); } diff --git a/Ghidra/Processors/Atmel/data/languages/avr8egcc.cspec b/Ghidra/Processors/Atmel/data/languages/avr8egcc.cspec index 2887d0e7d4..aec334bfd4 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8egcc.cspec +++ b/Ghidra/Processors/Atmel/data/languages/avr8egcc.cspec @@ -32,6 +32,7 @@ + @@ -39,25 +40,18 @@ - - + - - - - - - @@ -73,6 +67,14 @@ + + + + + + + + @@ -81,6 +83,9 @@ + + + @@ -101,8 +106,23 @@ - + + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/Atmel/data/languages/avr8gcc.cspec b/Ghidra/Processors/Atmel/data/languages/avr8gcc.cspec index 1d9b809ece..162a014c4e 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8gcc.cspec +++ b/Ghidra/Processors/Atmel/data/languages/avr8gcc.cspec @@ -31,13 +31,14 @@ + - + @@ -45,18 +46,12 @@ - - - - - - @@ -72,6 +67,14 @@ + + + + + + + + @@ -80,6 +83,9 @@ + + + @@ -102,15 +108,30 @@ + + + + + + + + + + + + + + + - - - - - + + + + + diff --git a/Ghidra/Processors/Atmel/data/languages/avr8iarV1.cspec b/Ghidra/Processors/Atmel/data/languages/avr8iarV1.cspec index 149e6c5ae5..2c1e32b4b6 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8iarV1.cspec +++ b/Ghidra/Processors/Atmel/data/languages/avr8iarV1.cspec @@ -5,6 +5,7 @@ + @@ -15,18 +16,18 @@ - + - - + + - - + + diff --git a/Ghidra/Processors/Atmel/data/languages/avr8imgCraftV8.cspec b/Ghidra/Processors/Atmel/data/languages/avr8imgCraftV8.cspec index b2f245c970..fd81d227e9 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8imgCraftV8.cspec +++ b/Ghidra/Processors/Atmel/data/languages/avr8imgCraftV8.cspec @@ -7,6 +7,7 @@ + diff --git a/Ghidra/Processors/Atmel/data/languages/avr8xmega.pspec b/Ghidra/Processors/Atmel/data/languages/avr8xmega.pspec index 5ab6644e0c..38cdd9fb76 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8xmega.pspec +++ b/Ghidra/Processors/Atmel/data/languages/avr8xmega.pspec @@ -20,6 +20,12 @@ + + + + + + @@ -1476,6 +1482,8 @@ + + diff --git a/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR8_ElfRelocationHandler.java b/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR8_ElfRelocationHandler.java new file mode 100644 index 0000000000..d3db091555 --- /dev/null +++ b/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/relocation/AVR8_ElfRelocationHandler.java @@ -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; + } + } + +}