13

I'm currently working on a C program in the LPCXpresso (eclipse-based) tool-chain on Windows 7, an IDE with gcc targeting the an NXP Cortex M3 microprocessor. It provides a simple way to compile-link-program the microprocessor over JTAG. The result of a build is an AXF file (ELF format) that is loaded by a debug configuration.

The loaded program resides in Flash memory from 0x00000 to 0x3FFFB. I'd like to include a 4-byte CRC-32 at 0x3FFFC to validate the program at start-up. I added another section and use the gcc __attribute__ directive to access that memory location.

uint32_t crc32_build __attribute__ ((section(".text_MFlashCRC")));

To compute and store the CRC-32 value, my plan was to use SRecord with the following post-build steps:

arm-none-eabi-size "${BuildArtifactFileName}"
arm-none-eabi-objcopy -O binary "${BuildArtifactFileName}" "${BuildArtifactFileBaseName}.bin"
checksum -p ${TargetChip} -d "${BuildArtifactFileBaseName}.bin"
../util/srec_cat "${BuildArtifactFileBaseName}.bin" -binary -crop 0 0x3FFFC -fill 0xFF 0x00000 0x3FFFC -crc32-b-e 0x3FFFC -o "${BuildArtifactFileBaseName}.crc.bin" -binary
echo ""
echo "CRC32:"
../util/srec_cat "${BuildArtifactFileBaseName}.crc.bin" -binary -crop 0x3FFFC 0x40000 -o - -hex-dump

This creates a binary with a checksum (necessary for bootloader) and then computes the CRC over the used Flash memory, storing the CRC value at 0x3FFFC.

However, I don't think I can load the binary file using the debugger. There is a built in programming utility with LPCXpresso that can load the modified binary file, however, that doesn't let me debug. I believe I can then try to start a debugging session with the original AXF file using "attach-only" mode, however, this becomes cumbersome.

I've been able to use readelf to inspect the crc32_build variable in the AXF file. Is there a way to edit the variable in the AXF file? Is there an industry-standard approach to inserting a CRC as a post-build step?

superlou
  • 679
  • 1
  • 8
  • 21

1 Answers1

16

There is no industry standard that I am aware of. There are various techniques to do this. I would suggest that you use the crc32_build as an extern in 'C' and define it via a linker script. For instance,

  $ cat ld.script
  .text : {
    _start_crc_region = .;
    *(.text);
    _end_crc_region = .;
    crc32_build = .;
    LONG(CALC_CRC);
  }

You pass the value CALC_CRC as zero for a first invocation and then relink with the value set. For instance,

 $ ld --defsym=CALC_CRC=0 -T ld.script *.o -o phony.elf
 $ objcopy -j sections phony.elf -o phony.bin # sections means checksum 'areas'
 $ ld --defsym=CALC_CRC=`crc32 phony.bin` -T ld.script *.o -o target.elf

I use this technique to add digital signing to images; it should apply equally well to crc values. The linker script allows you to position the variable, which is often important for integrity checks like a CRC, but wouldn't matter for a simple checksum. A linker script also allows you to define symbols for both the start and end of the region. Without a script, you need some elf introspection.

You can of course extend the idea to include init data and other allocated sections. At some point you need to use objcopy to extract the sections and do the integrity check at build time. The sections may have various alignment constraints and you need to mimic this (in phony.bin above) on the host when doing the build time crc calculation.

As a bonus, everything is already done when you generate an srec file.

If you have trouble with --defsym, you can just pre-process the ld.script with sed, awk, perl, python, etc and substitute text with a hex value where CALC_CRC is.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • This seems like a good approach. I have to figure out how to use this with the minimal disruption to the LPCXpresso tool-chain, as it already auto-generates the linker scripts. If I understand this right, I'd also need to modify the makefile to replace their `ld` command with one that defines CALC_CRC? – superlou Jun 12 '14 at 17:43
  • Yes, that is correct. You probably have to alter the make anyways as you need to do **two** links. The first with a dummy/zero CRC. The 2nd that will actually populate the CRC. The `ld -r` (partial linking) may also be useful. However, I used the method above, but the issue in my case was determining the final size as this was included in the certificate (actually you get the same with `_end_crc_region-_start_crc_region`. You may have to subtract the final crc size when calculating the build CRC; Ie, don't include the zero in the dummy image. – artless noise Jun 12 '14 at 18:44
  • You can use the `__attribute section` for a CRC **input sections**, but pretty much you must use a custom linker script and put the **input section** in some **output section** (because no standard exists). So that method will give you the same end solution (in my opinion) and you might as well define the space in the linker script. Your code needs to know the size (compiled in image); if you CRC the CRC calling code. Alternatively, you can pad to some pre-determined maximum size, but that wastes run time. – artless noise Jun 12 '14 at 18:52
  • If I wanted to extend this over the .data section as well, could the ld script be configured to keep the CRC value at the end of .data? I've been running into an issue there since it should be a const, which is normally part of .text, so is mapped before .data. Is there an alternative to running the CRC on all of .text, skipping over the CRC location, then continuing with .data? – superlou Jul 01 '14 at 18:47
  • `objcopy -j .text -j .data` will copy both sections. However, the runtime CRC will have to *jump* pointers, so I would just store two CRC values and calculate them separately. I don't think you gain much by doing both in one value? `const` is a 'C' construct. For the linker, `.data` is from 'initdata', which is the initial data values. This section is copied to the final `.data` address at startup. So, your CRC of the data **must** run before anything changes any 'C' global/static data; or you may define some special `.data` for certain input files and not CRC it. Asm or careful C only. – artless noise Jul 01 '14 at 19:10