Go Down

Topic: Understanding the .hex file (Read 2 times) previous topic - next topic

BKnight760

Frank, thank you for your reply. 

Is there a program that will dis-assemble these .hex files?  Could you point me to one?

I will gladly run the disassembly and check what actual assembler instructions are being used.  Perhaps that will provide some clarity.

AWOL

You could look at the disassembly of the sketch - could save some time.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

BKnight760

You're right, no need to disassemble if the original assembly listing still exists somewhere.  Any idea what it's named?

I've found the /Temp/build.../ directory where the code is compiled, but don't have anything that looks like assembly.

I have:

blink_1MHz.cpp         <--- the original source code.
blink_1MHz.cpp.eep   <--- just a single EOF record for the .hex file. 
blink_1MHz.cpp.elf     <--- Bunch of garbled text (Looks like it could be a raw hex file)
blink_1MHz.cpp.hex   <--- .hex file as shown earlier.
blink_1MHz.cpp.o      <--- object file

There's a few more .o files listed there, but I assume the object files aren't what I'm looking for.  I was expecting to find a .s or a .lss file, but didn't see one.

BKnight760

#8
Apr 25, 2011, 11:53 pm Last Edit: Apr 25, 2011, 11:58 pm by BKnight760 Reason: 1
ok, I found how to disassemble the .cpp.elf file using avr-objdump -S command from /hardware/tools/avr/bin/

That worked and now I have the following assembler:

Code: [Select]

C:\blink_1MHz.cpp.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   }
 
   return(0);
}

void ioinit (void)
  0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end>
  4: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
  8: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
  c: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 10: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 14: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 18: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 1c: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 20: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 24: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 28: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 2c: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 30: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 34: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 38: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 3c: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 40: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 44: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 48: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 4c: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 50: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 54: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 58: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 5c: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 60: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>
 64: 0c 94 51 00 jmp 0xa2 ; 0xa2 <__bad_interrupt>

00000068 <__ctors_end>:
 68: 11 24       eor r1, r1
 6a: 1f be       out 0x3f, r1 ; 63
 6c: cf ef       ldi r28, 0xFF ; 255
 6e: d8 e0       ldi r29, 0x08 ; 8
 70: de bf       out 0x3e, r29 ; 62
 72: cd bf       out 0x3d, r28 ; 61

00000074 <__do_copy_data>:
 74: 11 e0       ldi r17, 0x01 ; 1
 76: a0 e0       ldi r26, 0x00 ; 0
 78: b1 e0       ldi r27, 0x01 ; 1
 7a: e2 e0       ldi r30, 0x02 ; 2
 7c: f1 e0       ldi r31, 0x01 ; 1
 7e: 02 c0       rjmp .+4       ; 0x84 <.do_copy_data_start>

00000080 <.do_copy_data_loop>:
 80: 05 90       lpm r0, Z+
 82: 0d 92       st X+, r0

00000084 <.do_copy_data_start>:
 84: a0 30       cpi r26, 0x00 ; 0
 86: b1 07       cpc r27, r17
 88: d9 f7       brne .-10     ; 0x80 <.do_copy_data_loop>

0000008a <__do_clear_bss>:
 8a: 11 e0       ldi r17, 0x01 ; 1
 8c: a0 e0       ldi r26, 0x00 ; 0
 8e: b1 e0       ldi r27, 0x01 ; 1
 90: 01 c0       rjmp .+2       ; 0x94 <.do_clear_bss_start>

00000092 <.do_clear_bss_loop>:
 92: 1d 92       st X+, r1

00000094 <.do_clear_bss_start>:
 94: a0 30       cpi r26, 0x00 ; 0
 96: b1 07       cpc r27, r17
 98: e1 f7       brne .-8       ; 0x92 <.do_clear_bss_loop>
 9a: 0e 94 53 00 call 0xa6 ; 0xa6 <main>
 9e: 0c 94 7f 00 jmp 0xfe ; 0xfe <_exit>

000000a2 <__bad_interrupt>:
 a2: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>

000000a6 <main>:
{
   //1 = output, 0 = input
   DDRB = 0b11111111; //All outputs
 a6: 8f ef       ldi r24, 0xFF ; 255
 a8: 84 b9       out 0x04, r24 ; 4
   DDRC = 0b11111111; //All outputs
 aa: 87 b9       out 0x07, r24 ; 7
   DDRD = 0b11111110; //PORTD (RX on PD0)
 ac: 8e ef       ldi r24, 0xFE ; 254
 ae: 8a b9       out 0x0a, r24 ; 10
{
   ioinit(); //Setup IO pins and defaults

   while(1)
   {
PORTC = 0xFF;
 b0: 3f ef       ldi r19, 0xFF ; 255
 b2: 38 b9       out 0x08, r19 ; 8
PORTB = 0xFF;
 b4: 35 b9       out 0x05, r19 ; 5
PORTD = 0xFF;
 b6: 3b b9       out 0x0b, r19 ; 11
 b8: 84 ef       ldi r24, 0xF4 ; 244
 ba: 91 e0       ldi r25, 0x01 ; 1
 bc: 0b c0       rjmp .+22     ; 0xd4 <main+0x2e>
...
//General short delays
void delay_ms(uint16_t x)
{
 uint8_t y, z;
 for ( ; x > 0 ; x--){
   for ( y = 0 ; y < 90 ; y++){
 ca: 2f 5f       subi r18, 0xFF ; 255
 cc: 2a 35       cpi r18, 0x5A ; 90
 ce: b9 f7       brne .-18     ; 0xbe <main+0x18>

//General short delays
void delay_ms(uint16_t x)
{
 uint8_t y, z;
 for ( ; x > 0 ; x--){
 d0: 01 97       sbiw r24, 0x01 ; 1
 d2: 11 f0       breq .+4       ; 0xd8 <main+0x32>
 d4: 20 e0       ldi r18, 0x00 ; 0
 d6: f3 cf       rjmp .-26     ; 0xbe <main+0x18>
PORTC = 0xFF;
PORTB = 0xFF;
PORTD = 0xFF;
delay_ms(500);

PORTC = 0x00;
 d8: 18 b8       out 0x08, r1 ; 8
PORTB = 0x00;
 da: 15 b8       out 0x05, r1 ; 5
PORTD = 0x00;
 dc: 1b b8       out 0x0b, r1 ; 11
 de: 84 ef       ldi r24, 0xF4 ; 244
 e0: 91 e0       ldi r25, 0x01 ; 1
 e2: 0b c0       rjmp .+22     ; 0xfa <main+0x54>
...
//General short delays
void delay_ms(uint16_t x)
{
 uint8_t y, z;
 for ( ; x > 0 ; x--){
   for ( y = 0 ; y < 90 ; y++){
 f0: 2f 5f       subi r18, 0xFF ; 255
 f2: 2a 35       cpi r18, 0x5A ; 90
 f4: b9 f7       brne .-18     ; 0xe4 <main+0x3e>

//General short delays
void delay_ms(uint16_t x)
{
 uint8_t y, z;
 for ( ; x > 0 ; x--){
 f6: 01 97       sbiw r24, 0x01 ; 1
 f8: e1 f2       breq .-72     ; 0xb2 <main+0xc>
 fa: 20 e0       ldi r18, 0x00 ; 0
 fc: f3 cf       rjmp .-26     ; 0xe4 <main+0x3e>

000000fe <_exit>:
 fe: f8 94       cli

00000100 <__stop_program>:
100: ff cf       rjmp .-2       ; 0x100 <__stop_program>


From my somewhat crude understanding of this assembly,
We start out at 0x00, which has the JMP 0x68 instruction.
Immediately we jump to 0x68.  It looks like most of this is overhead associated with setting up the timer.
Eventually we make it down to 0x9A where we do a jump to 0xA6 <main>.
This is where our actual program starts.

I can follow it through from there.

So what happened to the CFEF instruction that was in the .hex file?  Am I using the wrong instruction set?

In the assembler, I see it listed as:

Code: [Select]
 6c: cf ef       ldi r28, 0xFF ; 255

Why is this coming up as a load immediate instead of an RJMP?!

LDI's opcode is
Code: [Select]
1110 KKKK dddd KKKK

0b'1110 = 0xE

Shouldn't this instruction start with E, not C?


BKnight760

#9
Apr 26, 2011, 09:15 pm Last Edit: Apr 26, 2011, 09:27 pm by BKnight760 Reason: 1
I posted this question over on AVRFreaks.net and found the answer I was looking for, so I thought it would be prudent to post the answer here as well for people who are seeing the same issue:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=821010#821010

Turns out the bytes of the instruction are being reversed.

Code: [Select]
0x0C94  -->  0x940C

It appears that the second word for the double-word instruction is also reversed.
Code: [Select]
0x3400  -->  0x0034

Then 0x0034 is being shifted to the left one bit which results in 0x68.  This is done because the JMP address needs to end up on an even byte boundry, so the last binary digit in the jump address will always be zero.  They can save a bit (and thus address a space one power of two larger) if they store the bit-shifted number instead.

That's how the compiler is generating the JMP 0x68 assembler instruction.

I'm still not quite sure how to tell if the bytes have been reversed or not.  Is that just for double-word instructions?  Is there some documentation I missed that indicates this is how it works?

Go Up