- Getting the code size of a function in C
- Posted by Tosca Berisha on November 1st, 2005
I need to determine the size of a function or module since I need to
temporary relocate the function or module from flash into sram for
firmware updates.
How can I find that out during runtime. The
sizeof( myfunction)
generates an error saying "size of function unknown".
Thanks.
- Posted by Grant Edwards on November 1st, 2005
On 2005-11-01, Tosca Berisha <tberisha@uucp.gov> wrote:
You'll need to do something in your linker script to create
global symbols before and after the function. In your C code,
you should then be able to take the address of those global
symboals and do some math to determine the size.
--
Grant Edwards grante Yow! UH-OH!! We're out
at of AUTOMOBILE PARTS and
visi.com RUBBER GOODS!
- Posted by Arie de Muynck on November 1st, 2005
"Grant Edwards" ...
I've often seen compiler generated (optimized) code that jumps to common
sections of code, shared between functions. Labels around a function won't
help you when that happens.
Also, don't expect multiple functions in a module to stay in the same
sequence as they were in the source file, not even with all optimisation
off.
You could put the function as the only function in a **module** (a single
source file), which is also the only way I know with a (GNU) linker script
to put labels before and after it.
Regards,
Arie de Muynck
- Posted by Grant Edwards on November 1st, 2005
On 2005-11-01, Arie de Muynck <send.spam.to@spammer.org> wrote:
Such labels will allow him to determine the size of a function
(which is what he asked for). I didn't guarantee that answering
his question would solve his problem. 
Ordering is probably not guaranteed, but I've never seen it
change.
If you're using GCC, the easiest thing to do is to put the
function in question in its own section using
__attribute__((section "whatever")). Then you can put labels
at the start and end of section "whatever". Or you can define
a global symbol having the value of the size of the section
(which even more directly answers the original question).
Of course you could also put all functions in individual
sections using -ffunction-sections.
--
Grant Edwards grante Yow! You were s'posed
at to laugh!
visi.com
- Posted by Tosca Berisha on November 1st, 2005
Arie de Muynck wrote:
So then the only proper way would be to access the symbol table and see
whats the next entry after my function and get the difference between
the two.
Is there a standard way of accessing the symbol table?
For now (after reading Grants answer, thank you) I created a dummy
function after the needed function, and I am getting the size by
subtracting the pointers to those functions to get the size. This linker
I am using seems to keep the functions in the same order as written in
the .c file.
But I don't like relying on this solution, so I still seek for an
alternative.
Thanks Arie,
Tosca
- Posted by Tauno Voipio on November 1st, 2005
Tosca Berisha wrote:
If you're using GCC, probably you do not need to
copy anything, just locate your function to the initialized
data section:
/* Write unlock sequence */
static void unlock(void) __attribute__((section(".data")));
static void unlock(void)
{
FLASHMEM[KEYLOC1] = KEY1;
FLASHMEM[KEYLOC2] = KEY2;
}
This is the Flash unlock routine from an embedded
system.
--
Tauno Voipio
tauno voipio (at) iki fi
- Posted by Grant Edwards on November 1st, 2005
On 2005-11-01, Tauno Voipio <tauno.voipio@INVALIDiki.fi> wrote:
That works, but it can be a bit of a waste since the function
is sitting in both flash and RAM 100% of the time. If there
are multiple routines that need to be run from RAM at different
points in time, you can save a bit of RAM by overlaying them.
--
Grant Edwards grante Yow! I'll show you MY
at telex number if you show
visi.com me YOURS...
- Posted by johnspeth@yahoo.com on November 1st, 2005
Tosca Berisha wrote:
What you want to do is highly non-portable but try this working code
snippet I use for the MSP430:
// Blinks the LED
void codeFunction(void)
{
uartPrintf(": BLINK Press ESC to quit\r\n");
for(;
{
if(uartGetByte() == ESC) break;
LED_ON(P3OUT,BIT0);
delay(100);
LED_OFF(P3OUT,BIT0);
delay(100);
}
}
void codeFunction_END(void) { }
// Executes the BLINK command
void funcBLINK(int count,char *cmd,char *arg1,char *arg2)
{
byte codeRam[90];
size_t loadSize;
void (*pfnFunction)(void);
USE(count);
USE(cmd);
USE(arg1);
USE(arg2);
loadSize = (size_t)(codeFunction_END) - (size_t)(codeFunction);
uartPrintf(": BLINK Load size = %u\r\n",loadSize);
if(loadSize >= sizeof(codeRam))
{
uartPrintf(": BLINK Can't load code\r\n");
}
else
{
// Copy the code to RAM
memset(codeRam,0,sizeof(codeRam));
memcpy(codeRam,codeFunction,loadSize);
// Point to the function starting in RAM
pfnFunction = (void (*)(void))(codeRam);
// Execute from RAM
pfnFunction();
uartPrintf(": BLINK ok\r\n");
}
}
Note that delay() and uartPrintf() and uartGetByte() do NOT get copied
to RAM. That's part of the challenge.
JJS
- Posted by Tauno Voipio on November 1st, 2005
Grant Edwards wrote:
The amount of code needed in RAM for Flash writing is pretty
small: about 250 bytes on an ARM for garden-variety AMD Flashes.
--
Tauno Voipio
tauno voipio (at) iki fi
- Posted by Grant Edwards on November 1st, 2005
On 2005-11-01, Tauno Voipio <tauno.voipio@INVALIDiki.fi> wrote:
But where is the "flash writing" code getting the data?
In cases I've dealt with the "flash writing" code has to
impliment some sort of communications protocol in order to
receive the data to be programmed into flash. In the product
I'm working with right now, it takes 3KB of code to do a flash
update. That's a pretty significant chunk out of my 32KB of
RAM.
--
Grant Edwards grante Yow! Xerox your lunch
at and file it under "sex
visi.com offenders"!
- Posted by Tauno Voipio on November 1st, 2005
Grant Edwards wrote:
You do not need to keep the whole chunk in RAM at the same time.
Also, only the inner loop of a Flash writer is necessary to be
kept in RAM, the rest can reside in the Flash. The code responsible
for the handling from the unlock sequence till the chip responds
ready to poll has to be in RAM, but this is for erasing a segment
or writing a single byte. The rest of code can be safely in the
Flash without any problems.
The incoming data is usually transferred in some kind of chunks
(e.g. 128 bytes with Xmodem). It's no too difficult to keep
one chunk in the RAM and read more when that's written.
--
Tauno Voipio
tauno voipio (at) iki fi
- Posted by diablovision@yahoo.com on November 1st, 2005
Tosca Berisha wrote:
In ELF files generated by GCC, the symbol table has not only the name,
type (FUNC), and address of each symbol, but its size as well. Thus the
symbol table in the ELF file will tell you how big the code for the
function is; something like objdump usually does not print out this
information, but it is there.
- Posted by Grant Edwards on November 1st, 2005
On 2005-11-01, Tauno Voipio <tauno.voipio@INVALIDiki.fi> wrote:
You're right. I could split up the loader and keep part of it
in flash, but it's extra work and it doesn't buy me anything.
Once the decision is made to update flash, the entire RAM space
becomes available. The data that's there belongs to an
application that's being erased. It's a lot simpler to just
copy the entire loader into RAM and run it from there. Up
until that point, the loader is using 0 bytes of RAM.
It could, but there's no advantage to doing so.
Right.
--
Grant Edwards grante Yow! The Osmonds! You are
at all Osmonds!! Throwing up
visi.com on a freeway at dawn!!!
- Posted by Grant Edwards on November 1st, 2005
On 2005-11-01, diablovision@yahoo.com <diablovision@yahoo.com> wrote:
The ELF file isn't available to the program at run-time. It's
quite simple to put global simbols at the beginning and end of
a section. Then all you have to do in C is declare those
symbols as external char arrays.
--
Grant Edwards grante Yow! I'm having an
at EMOTIONAL OUTBURST!! But,
visi.com uh, WHY is there a WAFFLE
in my PAJAMA POCKET??
- Posted by Mike Harrison on November 2nd, 2005
On Tue, 01 Nov 2005 21:31:35 -0000, Grant Edwards <grante@visi.com> wrote:
.... so just assume the function occupies all the RAM, and copy that many bytes.
- Posted by Hans-Bernhard Broeker on November 2nd, 2005
Tosca Berisha <tberisha@uucp.gov> wrote:
No way. A portable program has no way at all of finding this out,
i.e. it cannot be done "in C" at all. And even a non-portable
program, using features outside the C programming language proper,
typically won't be able to do this at run-time. Stuff like this has
to be set up at link time, the latest, and often you'll need to do it
at compile time already. There's even a non-negligible probability
that it can't be done at all, or only in assembly.
Some toolsets have special extensions (#pragma or __attribute__()) in
the source, or some magic incantation to put in the linker commands)
that tell the linker a particular function will be stored in a
location different from the one it's meant to run from.
--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
- Posted by Grant Edwards on November 2nd, 2005
On 2005-11-02, Mike Harrison <mike@whitewing.co.uk> wrote:
Sure, but once you've put in a label so you know where the
function starts, putting in a second one so you know where it
ends only takes a couple more keystrokes.
--
Grant Edwards grante Yow! An air of FRENCH
at FRIES permeates my
visi.com nostrils!!
- Posted by Hans-Bernhard Broeker on November 2nd, 2005
Grant Edwards <grante@visi.com> wrote:
Except that unlike the single starting point, which usually must exist
for the C function to be callable from unrelated translation units,
there's no particular reason for a given C function to even *have*
exactly one end where such a label could be put. Nor is there a
requirement that the entry point be at the start of the code region
for that function.
There's not even a requirement that a C compiler would have to
translate a single function to a single, consequtive block of code.
Optimization by function tail merging exists.
As I stated elsewhere in this thread: it's easily possible that on a
given platform the only way of pulling this off is by coding all the
relevant parts in assembler.
--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
- Posted by Grant Edwards on November 2nd, 2005
On 2005-11-02, Hans-Bernhard Broeker <broeker@physik.rwth-aachen.de> wrote:
Nonsense. There is some address X such that all bytes in the
function have addresses less than X. Unless you've got some
weird non-linear memory addressing scheme.
That's why adding global labels before and after the function
is much safer than useing the function pointer for anything.
It may not be a requirement, but I've never seen a C compiler
that didn't. This is comp.arch.EMBEDDED. We've got to work
with real-world toolchains here, not some imaginary "could do
anything the ISO spec allows" toolchain. comp.lang.c is that
way --->
I've been doing embedded C for 20 years on a dozen different
target architectures and at least as many toolchains. I've
never seen a target/toolchain where what the OP wants isn't
easily doable with some trivial linker-script hacking.
--
Grant Edwards grante Yow! WHOA!! Ken and
at Barbie are having TOO
visi.com MUCH FUN!! It must be the
NEGATIVE IONS!!
- Posted by Tauno Voipio on November 2nd, 2005
Grant Edwards wrote:
OK. Have a look at the Hi-Cross C Compiler. It translates
every function into a separately linked unit. The units
are linked in only if there are references to them. The
addresses allocated by the linker for consecutive functions
are not consecutive. For the reasons in this discussion
(Flash writer) I tried to find the function sizes, but
failed miserably.
The binary file created was also a jumble of criss-
crossed function-size pieces, so that I had to make
an extra pre-sorting and merge pass before writing
to Flash.
My guess is that the functions were ordered by the
stored call tree order collapsed in a weird way.
--
Tauno Voipio
tauno voipio (at) iki fi