Hi,
I have been trying to implement a checksum on an ARM9 using the RealView Armcc compiler. To place my checksum at the proper location, I use:
#define INTEGRITY_COMPARE_VAL_ADDR 0x1006FFFF #define INTEGRITY_COMPARE_VAL 0x12345678 const volatile unsigned char integrity_compare_val __attribute__((at(INTEGRITY_COMPARE_VAL_ADDR))) = INTEGRITY_COMPARE_VAL;
At startup, I compute the checksum over all memory from 0x10000000 to 0x1000FFFE. My naive approach was to then set the definition of INTEGRITY_COMPARE_VAL to this checksum, recompile, then run successfully. While this works occasionally, by performing diffs of the generated hex files, I've found that changing the INTEGRITY_COMPARE_VAL (and really the value at the location of variable integrity_compare_val), the hex file differs at more locations than just the one expected spot. The other differences don't appear to be tied to the compare value explicitly since "12345678" only occurs once in the hex files and at the proper location. Is there a compiler option I'm missing or is this expected behavior? I have optimization at level 0.
I have looked at Keil's appnote on using the CHECK8 utilitiy (http://www.keil.com/support/docs/494.htm) to sign the hex file but was avoiding this approach since we may want to move onto a more robust signing procedure (32-bit checksum, CRC-16, MD5, etc.) in the future. In addition, CHECK8 doesn't want to run on Windows 7 64-bit. On past projects, I've taken the external signing (like CHECK8) approach, but on those platforms had a tool to create a hex file that covered the entire memory space, making custom checksums much easier.
Would appreciate any tips or advice.
Thank you, Louis
Note that your code will not contain any value at your specific address.
RAM doesn't keep any contents between power cycles. So the startup code will contain an optionally compressed copy of your checksum value. And the startup code will decompress and copy that value to the address of your variable. That will result in an unknown number of bytes changing when you change the checksum value to store.
It really is better to use the post step of the build process to perform some action and glue the result of that action together with the normal binary. Or to convert the hex file into binary format and then patch that binary to store a checksum in the last four bytes (potentially first extending the size of the binary file to match the full flash size).
So if I understand right, there is a section that holds a compressed copy of the values to be set during C environement initialization? Since some data dependent on the checksum has to be in there (no matter what), the only way to get the value at the right spot in the hex/binary file without incurring the C initialization copy is to physically put it at it's location in the hex/binary.
It doesn't look like Keil's Hex2Bin will work on 64-bit Windows. Could I accomplish the insertion by reading the hex file and assuming unspecified addresses are all 0x00, or is there additional data in the binary. If I understand things right, the binary would be much easier to process, but at this point I'm just looking for any solutions. I've found a couple other intelhex2bin applications, but is there anything special about Keil's hex files that would bite me?
A problem is what type of memory you have.
If you have an initialized variable in RAM, the startup code needs to copy that value to the variable before entering main(). And all variables that haven't been given an initial value needs to be zero-filled by the startup code.
If you have an initialized const variable in flash, the data there is basically "code" located at a specific location in the flash. So the hex file can specify the address and the value, and the flash gets the correct value when you flash the device. No involvement of the startup code.
In short - you can manually add the value to your project and get the compiler + linker to produce an output file that contains your value without breaking something else. But only if the compiler considers the value as fixed flash contents, and not as a variable to initialize.
You haven't told what chip you have, so I don't know if you try to place a value at end of RAM or at end of flash. The runtime startup code can't write to RAM. While data stored in flash obviously requires that the address you specified is part of the flash.
Another thing - you specified an address 0x1006FFFF for you sum. That seems to be the last byte of a memory region. And your variable integrity_compare_val is of the type unsigned char, which has size 1. But the value you want to assign is 0x12345678 which is a 32-bit value. A 32-bit variable stored at the end of a memory region should have 0xFC at the end of the address.
Fixed flash contents would be fine. Is there a directive or a syntax trick to get that? I was hoping that "const" would do that, but I guess not based on the changing values elsewhere.
Sorry about the confusing memory locations. I copypasted my code in between a changeover from 32-bit to 8-bit checksum and failed to fix. The processor is an AT91SAM9263 with an 0x0007_0000 long Flash memory starting at 0x1000_0000. I'd prefer to create a 32-bit checksum (would go with 8-bit if have to use Keil's tools) so the code memory would be from 0x1000_0000 to 0x1006_FFF8 and position the checksum at 0x1006_FFFC.