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
http://www.keil.com/support/docs/1584.htm
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
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)
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!
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).
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...
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.
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?
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:
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?