Tool to analyze size of ELF sections and symbol - c

I need a way to analyze output file of my GCC compiler for ARM. I am compiling for bare metal and I am quite concerned with size. I can use arm-none-eabi-objdump provided by the cross-compiler but parsing the output is not something I would be eager to do if there exists a tool for this task. Do you know of such a tool existing? My search turned out no results.
One more thing, every function in my own code is in its own section.

You can use nm and size to get the size of functions and ELF sections.
To get the size of the functions (and objects with static storage duration):
$ nm --print-size --size-sort --radix=d tst.o
The second column shows the size in decimal of function and objects.
To get the size of the sections:
$ size -A -d tst.o
The second column shows the size in decimal of the sections.

The readelf utility is handy for displaying a variety of section information, including section sizes, e.g.:
arm-none-eabi-readelf -e foo.o
If you're interested in the run-time memory footprint, you can ignore the sections that do not have the 'A' (allocate) flag set.

When re-visiting this question 10 years later one must mention the little Python-based wrapper for readelf and nm that is elf-size-analyze:

puncover uses objdump and a few other gcc tools to generate html pages you can easily browse to figure out where your code and data space is going.
It's a much nicer frontend than the text output of the gcc tools.

Related

UNIX: C: cc compiler. Command Line: How to display the binary file header on screen

I am looking for the unix command to display the header portion in Hex for any excutable that has been compiled by the cc compiler.
I had this once and now I cant remember it.
I just want to see what the compiler code that is at the start of any c programs that I compile
I am aware that I can use 'hexdump [filename]' however that doesnt isolate the header portion .
Hope i have explained myself well enough.....
The command readelf is available on most Linux systems and has the ability to display many parts of an ELF file. You can use readelf -H to get a short synopsis of the various options.
To get just the file header you can use readelf -h or readelf --fileheader to display the file header.
To see it in hex, you can use the command xxd. Given that the elf header is 64 bytes (on a 64-bit machine), you can use xxd -l 64
Objdump command in Linux is used to provide thorough information on object files. This command is mainly used by the programmers who work on compilers, but still its a very handy tool for normal programmers also when it comes to debugging. In this article, we will understand how to use objdump command through some examples.
Basic syntax of objdump is :
objdump [options] objfile...
There is a wide range of options available for this command.
For example, factorial is the c program that I have to compiled.
1.Display object format specific file header contents using
-p option
The following example prints the object file format specific information.
$ objdump -p factorial
Display the contents of all headers using -x option
Information related to all the headers in the object file can be retrieved using the -x option.
objdump -x factorial

Can LD access the data at an address?

I'm writing some code for a project that uses a Kinetis processor. These processors have a Flash Config Field which is stored in flash at a particular address. If the wrong value gets written to that field, you can lock yourself out of your chip for good.
My code for this consists of a packed struct, an instance that specifies the .flashConfig section, some static asserts to ensure the struct is the required size, and the #define that gets written to the FSEC field (the important one) is as expected. Then in the linker script I have that section stored in the correct bit of flash. Additionally I have an ASSERT to see if I have the correct amount of data in that section.
This is all pretty good, but I'm still nervous (I've seen these chips gets themselves locked up, on several occasions now). What I want to do is add an extra assert to the linker script, something like:
ASSERT(BYTE_AT(0x40C) == 0xBE);
Is that possible?
I considered using objdump / objcopy to get dump this from a .bin in a post build step. However I'm building this on windows, so no grep / awk which would be nice and easy. Other people will also have to build this, so I don't want to rely on cygwin being installed or what not. Plus this is a little more removed than the linker, and therefore could easily be missed if someone removes the post_build script.
I don't want to rely on cygwin being installed or what not.
Write a C program that performs the same check objdump and grep would have done.
Plus this is a little more removed than the linker, and therefore could easily be missed if someone removes the post_build script.
Make the verification program invoke the linker, and then verify the result. That is, instead of
${LD} -o foo.bin ${LDFLAGS} ${OBJS} && ./post_build foo.bin
do this:
./build_and_verify -o foo.bin ${LDFLAGS} ${OBJS}

ESP8266: What can I do to overcome "section `.text' will not fit in region `iram1_0_seg'"?

What are general measures against the .text region not fitting into "iram1_0_seg" when linking for the ESP8266 using the xtensa GCC based toolchain?
I guess that the ESP8266s RAM is not big enough to hold certain functions. However, what can I do to move as many functions into flash as possible?
Here is an example of what the linker returns:
/home/user/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/bin/xtensa-lx106-elf-gcc -I/home/user/git/esp-open-sdk/sdk/include -I/home/user/git/esp-open-sdk/sdk/include/json -I/home/user/git/mart3/src/RTMain/ESP8266TargetGroup -Os -D__ESP8266__ -std=c99 -pedantic -Wall -Wpointer-arith -pipe -Wno-unused-parameter -Wno-unused-variable -Os -g -O2 -Wpointer-arith -Wundef -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH -ffunction-sections -fdata-sections -L/home/user/.arduino15/packages/esp8266/hardware/esp8266/2.0.0/tools/sdk/lib -L/home/user/.arduino15/packages/esp8266/hardware/esp8266/2.0.0/tools/sdk/ld -Teagle.flash.512k0.ld -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static -Wl,--gc-sections src/code/CMakeFiles/FX6CodeObj.dir/FX6Generated/src-gen/fxfu___program1.c.obj src/code/CMakeFiles/FX6CodeObj.dir/FX6Generated/src/emptyHello/fxfu___helloart.c.obj src/code/CMakeFiles/FX6CodeObj.dir/FXStd/FXRTMain.c.obj src/code/CMakeFiles/FX6CodeObj.dir/FXStd/NamedList.c.obj -o src/ARTApp/ARTApp.out -Wl,--start-group src/ART/libART.a -lm -lgcc -lhal -lphy -lnet80211 -llwip -lwpa -lmain -lpp -lsmartconfig -lwps -lcrypto -laxtls -Wl,--end-group
/home/user/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld: src/ARTApp/ARTApp.out section `.text' will not fit in region `iram1_0_seg'
collect2: error: ld returned 1 exit status
I don't know about Arduino but if you were to program using the Espressif libraries found here https://github.com/esp8266/esp8266-wiki/raw/master/sdk/ then they have a lot of Macros for things such as that.
As an example the "main" of the ESP is put into flash using the following line.
void ICACHE_FLASH_ATTR user_init(){
If you trace the ICACHE... command you will find this define
#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text")))
If you then look through how espressif sets up the memory sections https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map .irom0.text is labelled as the flash memory. Basically anything with the ICACHE... command is loaded into flash memory anything without is not.
Again not sure how to translate this to Arduino code but it might be time to move away from the Arduino libraries if you are running out of flash space. You didn't specify which ESP breakout you are using and my mind may be playing tricks on me but I believe the ESP12-e uses a newer chip which has more flash memory then say the ESP01, just another option.
It is a little late to answer the question but I thought others may be interested in a possible solution. This is what I have done to figure out about the iram1_0_seg overflow error on ESP8266 nonos sdk based firmware.
In order to find out what functions are actually allocated in the iram1_0_seg section run the following command:
$ xtensa-lx106-elf-nm -av yourprogram.elf | uniq -u | grep "^4010*"
The 'yourprogram.elf' of course needs to be replaced with the name of your firmware elf file. All iram1_0_seg functions are in the range of 4010xxxx addresses, hence the grep 4010. Obviously, this command can only be executed when the elf has been generated. If the elf file can not be generated due to the iram1_0_seg overflow error, then it is necessary to remove some code. Or roll back to a version of your code that was still fitting and did not have the iram1_0_seg overflow error.
The output of the above nm command will end with a line such as:
$ 4010680c A _text_end
The iram1_0_seg is limited to 0x8000 bytes on the ESP8266. In the above example, I have '0x680c' bytes allocated and therefore there is enough room. The nm command will list all functions allocated in the iram1_0_seg segment. Please look which of the functions are maybe not needed to be allocated in RAM. Most functions can run out of FLASH, but if you don't mark them with ICACHE_FLASH_ATTR, then the functions end up in RAM (and use up the 0x8000 bytes).
In case you see functions that should be in FLASH (but aren't), that actually come from the standard libraries libc.a or libgcc.a, then you have a good chance to make room in the iram1_0_seg segment. Let's take the example of memcpy, which is available in rom already and should not be needed at all in any library. The reason why it is anyway pulled from libc.a is due to the precedence that libraries take over PROVIDE statements in the linker script. Take a look at your eagle.rom.addr.v6.ld file (in your /esp-open-sdk/sdk/ld folder). In there you see the PROVIDE(memcpy=..) statement.
This tells you that memcpy is available in ROM. So, how to use the ROM function instead of the libc.a version? The easiest way is to simply remove memcpy from libc.a so that the linker takes the rom function. To be safe, I'm suggesting to make a copy of libc.a before, just in case something goes wrong. The following commands need to be executed in the library folder (where libc.a is located) in order to remove memcpy:
$ cp libc.a libc2.a
$ ar d libc2.a lib_a-memcpy.o
After you have changed your Makefile to link with -lc2 instead of -lc, the 'memcpy' function will be taken from ROM. Check with the above nm command to see that it was successful. memcpy should be no more listed in the 401 list. And maybe repeat with other libc.a functions (e,g, 'memcmp', 'strlen', 'strcpy', 'strcmp', ...).
This is how I brought the iram1_0_seg usage down to 0x680c bytes.
Similar procedure can be done with libgcc.a functions: __muldf3, __mulsf3, __umulsidi3, ...
You can try to change the memory allocation scheme by choosing another option in the Tools > MMU section. For example choose '16KB cache + 48KB IRAM (IRAM)' instead of '32KB cache + 32KB IRAM (balanced)'.

Width of symbols created by gcc's objectcopy

I am using objcopy to remove some necessary scripting to embed a resource file (zip file) in flash memory (ARM embedded thingy).
I am using objcopy like this:
arm-none-eabi-objcopy.exe -I binary -O elf32-littlearm -B arm --rename-section .data=.rodata input.zip input.zip.o
arm-none-eabi-nm.exe -S -t d input.zip.o
00006301 R _binary_input_zip_end
00006301 A _binary_input_zip_size
00000000 R _binary_input_zip_start
What I need to know is what is the width of the _end and _size symbols. I can only guess that the _start is an address which can be accessed like a byte array: extern uint8_t _binary_input_zip_start[];. And I am assuming that the _end and _size are of 'native' int-size, and I suppose I can safely assume I can interpret these as uint32_t.
However I can't be certain. I can't find anything "size" related in the docs of objcopy: https://sourceware.org/binutils/docs/binutils/objcopy.html
I'm not %100 sure if this will work, but try adding the option --sort-size to arm-none-eabi-nm. This is supposed to sort the symbols by size, by comparing them to the next symbol above. In combination with the -S option, it should print a size. Hopefully, this will help you deduce their width.
What ARM micro are you using? 32-bits is a good guess, but there are exceptions. If you happen to be using a Texas Instruments part, I can help a lot more.
I don't have an ARM project handy that I can test this on, but it's worth a shot. If that doesn't work, I'll keep digging.
Source: My knowledge, and double-checking via http://manned.org/arm-none-eabi-nm

How can compiling the same source code generate different object files?

After a long sequence of debugging I've narrowed my problem down to one file. And the problem is that the file compiles differently in two different directories, when everything else is the same.
I'm using CodeSourcery's arm gcc compiler (gcc version 4.3.3, Sourcery G++ Lite 2009q1-161) to compile a simple file. I was using it in one module with no issues and then I copied it to another module to use there. When it compiles, the object file is significantly different. The command line to compile the two files is identical (I used the linux history to make sure), and the 3 include files are also identical copies (checked with diff).
I did a binary compare on the two object files and they have a lot of individual byte differences scattered around. I did an objdump -D of both and compared them and there are a lot of differences. Here is dump1, dump2, and the diff. The command line is "
arm-none-eabi-gcc --std=gnu99 -Wall -O3 -g3 -ggdb -Wextra -Wno-unused -c crc.c -o crc.o".
How is this possible? I've also compiled with -S instead of -c and looked at the assembler output and that's identical except for the directory path. So how can the object file be different?
My real problem is that when I try to link the object file for dump2 into my program, I get undefined reference errors, so something in the object is wrong, whereas the object for dump1 gets no such errors and links fine.
For large scale software, there are many implementations are doing hashing on pointers. This is one major reason that cause result randomization. Usually if the program logic is correct, the order of some internal data structures could be different which is not harmful in most cases.
And also, don't compare the 'objdump -D' output, since your are compiling the code from different directory, the string table, symbol table, DWARF or eh_frame should be different. You will certainly get lots of diff lines.
The only comparison that makes sense is to compare the output of 'objdump -d' which only takes care of the text section. If text section is same(similar) then it can be considered as identical.
Most likely your file picks up different include files. This this the most likely reason.
Check that your include paths are exactly the same, paths in the include statements. They may point to different directories. C and C++ has a feature that when you #include abcd.h it tries to load abcd.h from the directory of the calling file. Check this.

Resources