This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Data placement at an absolute location using C



I know this topic has been addressed several times on this forum, but my need is slightly different.  I was able to edit the linker file to adjust the RAM segment and then add something like this as well:

alpha = 0x0200;

Then I declared an extern variable named alpha in my code file.  However, as far as I know, the only way to assign a value to this memory location is by using an instruction within the main function, which will end up being put in the code memory section.  Instead of this, I need to be able to write to this memory location outside of my code memory section, just as the initial vector interrupt values are stored in a location that's discontinuous from the rest of the programmed flash.  The reason for this is my checksum.  If I have to include the actual value of the checksum as part of an instruction in my code memory section, then the value would need to be recursive.  I tried declaring and initializing my extern variable alpha globally as a way around this:

extern unsigned short alpha = 0xAAAA;

main()

{

...

}

This did not work though.  Is there any other way to do this?

  • You can't have both an "extern" and an initializer. Essentially, a variable is defined right here, and may have an initializer, or it's defined somewhere else.

    unsigned short alpha = 0xAAAA;
  • Thanks for your response.  This doesn't quite work for me though.  In my linker file, I have:

    alpha = 0x0200;

    The way I understand it, the above statement is setting the memory location of alpha.  Then, in my program file, I have alpha declared globally, which correctly allocates memory starting at 0x200.  However, the only way I've been able to successfully initialize it is by doing so in my main function, which is what I'm trying to avoid.  I tried what you mentioned (initialize it in the same statement as when I declare it globally, without using "extern") but instead of initializing it, I got the following warning:

    symbol "alpha" being redefined

    This warning appeared next to the previously mentioned statement in my linker file (alpha = 0x200).  This tells me that when I try to initialize the variable in the same statement as declaring it globally, the compiler for some reason interprets it as trying to change the memory location.

  • Oh, I see. When you define a symbol in the linker command file, it's not the same sort of beast as a C variable. From a C context, all linker symbols are actually addresses, so you would need to access them like so (assumes EABI):

    extern char alpha;
    unsigned short alpha_value = (unsigned short)_symval(&alpha);

    The trouble is that you can't do this outside of a function except in C++ mode, and in C++ mode this is actually implemented by creating a stub function, which defeats your purpose anyway.

    You can, however, create a pointer which has the value of the integer you want, and cast that pointer to an integer:

    extern char alpha;
    const char * const alpha_ptr = α
    #define ALPHA ((unsigned short)alpha_ptr)

    You could then use ALPHA in your function; the actual value of alpha would not appear in the .text section, just in the .const section.

  • I'll try it this way.  But where do I actually specify the value to go into alpha?

  • In the linker command file, just as you have it.

  • I thought that saying this in the linker file:

    alpha = 0x0200

    would set the memory location that alpha's stored in to be 0x0200, as opposed to setting the actual value that's stored there.  Is this correct?  I don't see where I'm actually specifying the value of alpha.  It looks like your example code creates a pointer whose value pointed to is the memory location of alpha, as opposed to the value of alpha.  And then the "#define ALPHA" statement looks like ALPHA will just be the memory location of what alpha_ptr points to.

  • If you specified "alpha = 0x0200" outside of the MEMORY and SECTIONS specifiers, what you are actually doing is creating a linker symbol.  Linker symbols are different than C symbols.  Linker symbols effectively represent addresses.  The only way to access linker symbols from the C source code is to fake out the compiler by making it believe it is dealing with the address of some object which doesn't actually exist.  The C code will typically look like the address-of operator applied to a fake variable with the same name as the linker symbol, and the whole expression cast to a 32-bit unsigned integer.

  • It seems though that this solution still makes me specify the value at memory location 0x0200 in my main function, which defeats the purpose, as that value will end up in the code flash.

  • When you say "in my main function", do you really mean "the .text section containing the function code of main"?  If so, using

    const unsigned short alpha_value = ALPHA;

    will prevent the address from showing up in .text

  • I'm not worried about the address showing up.  I'm worried about the integer value to be stored in that address showing up.

  • The address is an integer value.  I think we're getting confused by each other's terminology.

    Let's take it one step at a time: Does your solution perform CRC on the .const section?

  • Well I'm not using CRC, but yes I am checking the .const section.  I'm checking everything I write to the flash except the initial values of the vector interrupts.  The reason for this is that I'm concerned with what shows up in the .hex file, as those are the values that will be written to the flash (besides the vector interrupts).

    As an example, let's say my checksum is 0xAAAA and I want to store it in 0x0200.  I can easily set aside alpha at 0x0200.  But what I'm trying to do is store 0xAAAA at that location without putting it in my main function (.text section).

    The only way I've been able to get this to work so far is by doing something like this:

    #pragma location = 0x200
    unsigned short alpha = 0xAAAA;

    void main(void)
    {
        alpha++;
        ..................
    }

    For some reason, it will only initialize alpha when I declare it this way if I use the "alpha++" in main.  I'm not sure why this is the case, but if I can't find any other solution then I'll have to deal with it for now.

  • In short: you perform checksum on everything but one special location (0x200).  The checksum value 0xAAAA must not appear anywhere else, such as .text, .const, .bss, .data, etc.  You want to set aside just that one location in the program, and the code you show accomplishes that, so I don't see any need for adding anything at all to the linker command file.  There are other ways to accomplish that, but none that are simpler.

    As to why alpha disappears, the optimizer and linker can aggressively about eliminate unused variables.  Is this the only apparent reference to alpha in your program?  Does the code to perform the checksum live outside of the program?

  • Well I'm only checking part of the code memory of the flash, so if I want I can store the checksum at 0x200 or somewhere else like information memory.  I chose to use 0x200 for starters.  But you're correct that I don't want 0xAAAA to appear anywhere else.

    My routine that calculates the checksum and compares to the value stored at 0x200 is part of the program.  I tested many different ways to have the variable properly initialize using the code I listed previously.  Even if I used any one of the following lines in the main program:

    alpha--;
    alpha+=1;
    unsigned short temp = alpha;
    // and a couple others

    the variable alpha would not be properly initialized despite using the code I listed in my previous post.  The only statement that preserved the initializing statement was "alpha++".  I find this very bizarre, but I suppose it could be related to my size optimization settings.

    EDIT: I tried turning optimization off, and I still have the same issue.

  • I cannot guess why that might be, I would need to see a test case.

  • Ok, well I'll keep working at it and hopefully figure something out that works a little bit more cleanly.  I very much appreciate your help, and I'm sorry we were having trouble communicating.

  • Try putting the extern variable containing the checksum into a section of its own, and adjust the linker command file to put that section into ROM for both load *and* run.  When computing the checksum, don't include ROM, or at least exclude the section of ROM containing your checksum variable.  In your checksumming code, refer to the variable (e.g. "alpha") via a declaration:

    extern far unsigned alpha; // checksum located in ROM

    The remaining issue is how to get the correct value stored there.  You can define alpha with 0 contents, e.g. in a small source file that declares its section then "unsigned alpha = 0;" and in your checksumming code if alpha contains 0, compute the checksum and display it somehow, else do the desired check against whatever is in alpha.  Run the program once to see the displayed checksum, then modify *only* the alpha-defining source file to change the 0 initializer to whatever the displayed checksum was, and relink.  The result should be a program that sees the correct checksum in alpha.

    Why bother to checksum in the first place?