tags:

views:

260

answers:

4

Hey, guys -

I'm writing a real-time operation system from scratch for a course project. I want to know the end address of my code after I download it to the chip, because I am planning to use the free memory for stack space and I need make sure that I won't overwrite the existing code.

I heard about __end variable provided by GCC is the end of the code, but I have no idea about what is the meaning of __end and how to use it in my code. Could anyone explain it a little bit or provide links to some materials, cos I couldn't google __end?

Thanks a lot.

A: 

Well, I'm not that familiar with GCC, but maybe you can do something like this:

long foo()
{
    int anything[0];
    return *(&anything - 1);
}

long endOfProgram()
{
    return stackPointer();
}

What I'm trying to do here is:

  1. Call endOfProgram()
  2. endOfProgram calls foo, so the address of endOfProgram is pushed onto the stack.
  3. Push anything[0] onto foo's stack.
  4. Grab the location of the element right before the address of anything, which should be memory location of endOfProgram.

Some of my syntax might be wrong, but I hope you can get the gist of what I'm trying to do.

EDIT:

... or just grab the value of a function pointer to endOfProgram. I guess that'd work too.

CookieOfFortune
That'll get you something near the location of the current stack pointer. It won't get you the end of the code segment.
Rob K
Well, I was assuming that if you put endOfProgram at the end of your code, it'll be placed at the very end... that might be an incorrect assumption.
CookieOfFortune
That might give you the address at the end of the current translation unit (or it might not, if the optimizer moves functions around), but it won't work if you have multiple translation units coming from multiple source files. You'll also need to know which translation unit gets linked in last.
Adam Rosenfield
Maybe output the code to disk to determine how big it is?
CookieOfFortune
A linker (or even the compiler) is free to move functions and data around - just because it's in a particular order in a source file does not mean it'll get laid out in memory the same way. To do this will require something in a linker configuration file and/or assembly language.
Michael Burr
Hahahah. Man, you should just use some inline assembly to do this.
toto
+2  A: 

You could use a linker script. In your C code, declare:

// call this whatever you want; the linker will fill this in with the address
// of the end of code
extern uint32_t endOfCode;

Then, in your linker script, add the following immediately after the definition of the .text section:

PROVIDE(endOfCode = .);

I'm not very familiar with linker scripts, so I can't provide a complete, working example. You'll have to take the default linker script (which I'm not sure how one obtains) and modify it as above, then use the -T option of the linker to specify it. Good luck!

Adam Rosenfield
+3  A: 

As Adam Rosenfeld points out, you need to use the linker control file to define one or more symbols for you that is located at the precisely correct place.

For gcc and binutils, you will be using ld's linker script syntax. Refer to ld's manual for all the details I'm leaving out here. It is a tad opaque, but you should spend some time with it if you are going to spend any significant amount of effort in the embedded world. It will pay off for you.

In the linker script, you want to define a symbol before your .text segment, and one after.

Adam mentions the PROVIDE() syntax, which will work. But you may not need to wrap the definition in PROVIDE if you can guarantee that your name is unique. Note that this is a guarantee that you must be able to make, or you risk a lot of confusion later.

In my script, I just use something like:

__SDRAM_CS1 = 0x10000000;

to define the symbol with a constant address that refers (in this case) to the location we decided that the SDRAM controller will map the SDRAM memory, and in C I declare it like:

extern unsigned char __SDRAM_CS1[];

so that it can be used in code that needs to know where the SDRAM actually is.

For a symbol locating the end of the .text segment, you would have something like the following in the linker script

SECTIONS
{
    ...
    .text {
        _start_text = .;
        *(.text);
        ...
        _end_text = .;
    }
    ...
}

and declare the start and end symbols as

extern unsigned char _start_text[];
extern unsigned char _end_text[];

in C. Then, the start address is simply _start_text, and the length in bytes of the text segment is _end_text - _start_text.

Note that I've left out a lot of detail. You probably have sections named things other than .text that must be treated as if they were in the text segment. A prime example is read-only data which often can be located in the text segment safely because it is known to be const and in an embedded system you'd rather not copy it to valuable RAM if you don't have to. Also, initializers for the data segment, and the internally generated lists of constructors of global objects all get located near the text segment.

Whether you include such things in your image size is a design decision that you need to make after understanding what they are used for.

RBerteig
A: 

Instead of putting it at the end, could you instead just declare a large static array and use that, no fancy compiler or linker tricks?

TokenMacGuy
For embedded code, you almost always have to treat the linker script as part of the source kit in any case. The situation is different in user land under a full OS, of course.
RBerteig