This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Intel HEX - Start Linear Address Record

Hi there,

I'm working on a bootloader that uses a hex file.

What does this row do?

:0400000508000131BD

It breaks up to these:

: Start code
04 Byte count: 4
0000 Address
05 Record type: Start Linear Address Record
08000131 <--- is this a start address?
BD Checksum

Does it say the execution start (IP) address is 0x08000131? My main program range is from 0x08000000 to 0x0800261.
Or should I discard the line altogether?

Thanks.
-Mad D

  • Hello Neil,

    www.sbprojects.com/.../intelhex.htm is a much better one, my intention was to get a second opinion.

    Either way I don't think you understood my question which is specific to the Start Linear Address Record.

    -Mad D

  • Does it say the execution start (IP) address is 0x08000131? My main program range is from 0x08000000 to 0x0800261.
    Or should I discard the line altogether?

    Yes, this record does indicate that the bootloader should jump to address 0x08000131 in order to start the loaded program. However, it is not uncommon to have misconfigured linker scripts which generate wrong start addresses. You should double-check with the provider of the firmware image: either you use the Start Linear Address Record to start the program, or you ignore it and use the start address given to you by the firmware image provider.

  • Hello Mike,

    Thanks for the reply. The firmware hex file is generated from Keil uVision3.

    Maybe I should start from 0x08000131 and 0x08000000 both to check which one works... :o)

    -Mad D

  • No, it doesn't!

    The Intel Hex format is simply a way of encoding binary data (with address information) using only printable ASCII characters - it neither knows nor cares anything about the meaning of the data!

  • Maybe I should start from 0x08000131 and 0x08000000 both to check which one works... :o)

    This question should not really arise at all. Normally, the start address of the firmware is the start address of the CPU. For many embedded CPU's this would be 0. As another example, the Coldfire CPU fetches the start address from location 0 and jumps to it. However, when firmware is split into bootloader and main application, surely some way of passing control to main application must be thought of at design stage. That's where the start address should come from.

  • No. The Intel Hex format isn't just a format for encoding the data - also a format for encoding the start address for use by a loader.

  • Well, the address information in the Hex records tells whatever's handling those records where to put them - but it says nothing about the significance of those addresses, nor whether the records represent "code" or "data"...

  • No. The specific records:
    03 Start Segment Address Record
    04 Extended Linear Address Record
    05 Start Linear Address Record
    doesn't encode data. They encode meta-data. In this case the start address of the binary.

    If just flashing a device, they get thrown away. But when fed to a loader, they are used to set up the program counter (and optionally a code segment register, in case of a 8086 segmented address space).

  • Hello Mike,


    For many embedded CPU's this would be 0.

    You are absolutely right.


    However, when firmware is split into bootloader and main application, surely some way of passing control to main application must be thought of at design stage. That's where the start address should come from.

    I am in the design phase, so Im trying to understand how the start address is handled in the hex file.

    A extract from the map file:

    Memory Map of the image
    
      Image Entry point : 0x08000131
    
      Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00002618, Max: 0x00020000, ABSOLUTE)
    
        Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x000024f4, Max: 0x00020000, ABSOLUTE)
    
        Base Addr    Size         Type   Attr      Idx    E Section Name        Object
    
        0x08000000   0x00000130   Data   RO         3056    RESET               stm32f10x_vector.o
        0x08000130   0x00000000   Code   RO         3065  * .ARM.Collect$$$$00000000  entry.o(mc_w.l)
        0x08000130   0x00000004   Code   RO         3068    .ARM.Collect$$$$00000001  entry2.o(mc_w.l)
        0x08000134   0x00000004   Code   RO         3071    .ARM.Collect$$$$00000004  entry5.o(mc_w.l)
        0x08000138   0x00000008   Code   RO         3072    .ARM.Collect$$$$00000007  entry7.o(mc_w.l)
        0x08000140   0x00000004   Code   RO         3069    .ARM.Collect$$$$00002712  entry2.o(mc_w.l)
        0x08000144   0x00000008   Code   RO         3057    .text               stm32f10x_vector.o
        0x0800014c   0x00000024   Code   RO         3073    .text               init.o(mc_w.l)
    
    

    As you can see, the first 0x130 bytes are the RESET section. I'm not sure what this part is really doing...

    Appreciate the correspondence...

    -Mad D

  • Now that we have the map file, it's easier to see what's going on. I can see where 0x08000000 comes from: this is an STM32F10x device.

    As you can see, the first 0x130 bytes are the RESET section. I'm not sure what this part is really doing...

    The RESET section contains interrupt and exception vectors.

    I am in the design phase, so Im trying to understand how the start address is handled in the hex file.

    If I were to design a bootloader, I would ignore the start address record in the HEX file. The natural thing for the bootloader to do when passing control to main application is to emulate the CPU out of reset: the Cortex-M3 CPU will initialize the stack pointer with the value from location 0, then jump to address stored at location 4 (see Cortex-M3 manual for details.) Perhaps, you can get away with simply resetting the CPU and letting it run your main application.

  • "They encode meta-data. In this case the start address of the binary."

    Yes - that's exactly what I said.

    "But when fed to a loader, they are used to set up the program counter"

    That's an interpretation applied by the Loader - the Hex format itself gives no significance whatsoever to the address or the data.

    eg, as noted above, the loader might load the initial PC direct from that address, or indirectly - using it as a "pointer to" the actual start address.

    The Hex file itself knows nothing of this - it is all down to the loader, and the tools that created the file...

  • Hi Mike,

    Thanks for the reply.

    To put things into perspective, 0x08000000 - 0x0800012C is taken up by the "Table 61. Vector table for other STM32F10xxx devices" as stated in the manual.

    When we allocate 4 bytes for the last vector, 0x08000130 is the starting address. Do you know why the entry point is 0x08000131?

    -Mad D

  • Do you know why the entry point is 0x08000131?

    I think I do. 0x08000130 is the start address. By the way, it is possible to rewrite the scatter file in such a way that the start address is different. Then 1 is added to the address to indicate processor state (Thumb, as opposed to ARM) at program start. This (odd) address can be used with the BX instruction to jump to program start and switch processor state automatically. This isn't of much use for the Cortex-M3 since it can only be in Thumb state. It would be different if the CPU was, say, ARM7TDMI (supports both ARM and Thumb instructions.)

  • Program starting from 0x08000000:

    Memory Map of the image
    
      Image Entry point : 0x08010131
    
      Load Region LR_IROM1 (Base: 0x08010000, Size: 0x00002618, Max: 0x00010000, ABSOLUTE)
    
        Execution Region ER_IROM1 (Base: 0x08010000, Size: 0x000024f4, Max: 0x00010000, ABSOLUTE)
    
        Base Addr    Size         Type   Attr      Idx    E Section Name        Object
    
        0x08010000   0x00000130   Data   RO         3056    RESET               stm32f10x_vector.o
        0x08010130   0x00000000   Code   RO         3065  * .ARM.Collect$$$$00000000  entry.o(mc_w.l)
        0x08010130   0x00000004   Code   RO         3068    .ARM.Collect$$$$00000001  entry2.o(mc_w.l)
        0x08010134   0x00000004   Code   RO         3071    .ARM.Collect$$$$00000004  entry5.o(mc_w.l)
        0x08010138   0x00000008   Code   RO         3072    .ARM.Collect$$$$00000007  entry7.o(mc_w.l)
        0x08010140   0x00000004   Code   RO         3069    .ARM.Collect$$$$00002712  entry2.o(mc_w.l)
        0x08010144   0x00000008   Code   RO         3057    .text               stm32f10x_vector.o
        0x0801014c   0x00000024   Code   RO         3073    .text               init.o(mc_w.l)
    
    Disassembly
    
    
    0x08010128 039B LSLS r3,r3,#14 0x0801012A 0801 LSRS r1,r0,#0 0x0801012C 039D LSLS r5,r3,#14 0x0801012E 0801 LSRS r1,r0,#0 _main_stk: 0x08010130 F8DFD00C LDR.W sp,[pc,#12] ; @0x08010140 _main_scatterload: 0x08010134 F000F80A BL.W __scatterload_rt2 (0x0801014C) _main_init: 0x08010138 4800 LDR r0,[pc,#0] ; @0x0801013C 0x0801013A 4700 BX r0 0x0801013C 230D MOVS r3,#0x0D 0x0801013E 0801 LSRS r1,r0,#0 0x08010140 05D0 LSLS r0,r2,#23 0x08010142 2000 MOVS r0,#0x00 295: LDR R0, =__main 0x08010144 4800 LDR r0,[pc,#0] ; @0x08010148 296: BX R0 0x08010146 4700 BX r0 0x08010148 0131 LSLS r1,r6,#4 0x0801014A 0801 LSRS r1,r0,#0 __scatterload_rt2: 0x0801014C 4C06 LDR r4,[pc,#24] ; @0x08010168 0x0801014E 4D07 LDR r5,[pc,#28] ; @0x0801016C 0x08010150 E006 B 0x08010160 0x08010152 68E0 LDR r0,[r4,#0x0C] 0x08010154 F0400301 ORR r3,r0,#0x01 0x08010158 E8940007 LDM r4,{r0-r2} 0x0801015C 4798 BLX r3 0x0801015E 3410 ADDS r4,r4,#0x10 0x08010160 42AC CMP r4,r5 0x08010162 D3F6 BCC 0x08010152 0x08010164 F7FFFFE8 BL.W _main_init (0x08010138) 0x08010168 24D4 MOVS r4,#0xD4 0x0801016A 0801 LSRS r1,r0,#0 0x0801016C 24F4 MOVS r4,#0xF4 0x0801016E 0801 LSRS r1,r0,#0 383: {} 0x08010170 4770 BX lr 707: {}

    Program starting from 0x08010000:

    Memory Map of the image
    
      Image Entry point : 0x08000131
    
      Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00002618, Max: 0x00020000, ABSOLUTE)
    
        Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x000024f4, Max: 0x00020000, ABSOLUTE)
    
        Base Addr    Size         Type   Attr      Idx    E Section Name        Object
    
        0x08000000   0x00000130   Data   RO         3056    RESET               stm32f10x_vector.o
        0x08000130   0x00000000   Code   RO         3065  * .ARM.Collect$$$$00000000  entry.o(mc_w.l)
        0x08000130   0x00000004   Code   RO         3068    .ARM.Collect$$$$00000001  entry2.o(mc_w.l)
        0x08000134   0x00000004   Code   RO         3071    .ARM.Collect$$$$00000004  entry5.o(mc_w.l)
        0x08000138   0x00000008   Code   RO         3072    .ARM.Collect$$$$00000007  entry7.o(mc_w.l)
        0x08000140   0x00000004   Code   RO         3069    .ARM.Collect$$$$00002712  entry2.o(mc_w.l)
        0x08000144   0x00000008   Code   RO         3057    .text               stm32f10x_vector.o
        0x0800014c   0x00000024   Code   RO         3073    .text               init.o(mc_w.l)
    
    Disassembly
    
    
    0x08000128 039B LSLS r3,r3,#14 0x0800012A 0800 LSRS r0,r0,#0 0x0800012C 039D LSLS r5,r3,#14 0x0800012E 0800 LSRS r0,r0,#0 _main_stk: 0x08000130 F8DFD00C LDR.W sp,[pc,#12] ; @0x08000140 _main_scatterload: 0x08000134 F000F80A BL.W __scatterload_rt2 (0x0800014C) _main_init: 0x08000138 4800 LDR r0,[pc,#0] ; @0x0800013C 0x0800013A 4700 BX r0 0x0800013C 230D MOVS r3,#0x0D 0x0800013E 0800 LSRS r0,r0,#0 0x08000140 05D0 LSLS r0,r2,#23 0x08000142 2000 MOVS r0,#0x00 295: LDR R0, =__main 0x08000144 4800 LDR r0,[pc,#0] ; @0x08000148 296: BX R0 0x08000146 4700 BX r0 0x08000148 0131 LSLS r1,r6,#4 0x0800014A 0800 LSRS r0,r0,#0 __scatterload_rt2: 0x0800014C 4C06 LDR r4,[pc,#24] ; @0x08000168 0x0800014E 4D07 LDR r5,[pc,#28] ; @0x0800016C 0x08000150 E006 B 0x08000160 0x08000152 68E0 LDR r0,[r4,#0x0C] 0x08000154 F0400301 ORR r3,r0,#0x01 0x08000158 E8940007 LDM r4,{r0-r2} 0x0800015C 4798 BLX r3 0x0800015E 3410 ADDS r4,r4,#0x10 0x08000160 42AC CMP r4,r5 0x08000162 D3F6 BCC 0x08000152 0x08000164 F7FFFFE8 BL.W _main_init (0x08000138) 0x08000168 24D4 MOVS r4,#0xD4 0x0800016A 0800 LSRS r0,r0,#0 0x0800016C 24F4 MOVS r4,#0xF4 0x0800016E 0800 LSRS r0,r0,#0 383: {} 0x08000170 4770 BX lr 707: {} 0x08000172 4770 BX lr

    The explanation about the byte made sense, but I can't make sense of it when I check the map and the disassembly.

    I changed the start locations to check whether thats what you meant... What I am thinking is to have the bootloader in the lower address and then jump to the program in the :0400000508010131BC record. What do you think?

    -Mad D