We have a program in which a section is added named .proghead.
I can read elf .proghead section data by using following command,
$ readelf -x .proghead elf-binary-file
Hex dump of section '.proghead':
0x0058b960 00112233 00000000 00010000 00000000 .."3............
0x0058b970 15200704 00000000 00016904 00000000 . ........i.....
Now I have to access this section using a C/C++ program.
Can someone please help me in writing C/C++ code to read particular section in elf binary ?
Any help is highly appreciated .
What you need is to read section headers (Elf64_Shdr) to find section names and its offset. The relevant information lies in sh_name and sh_offset fields. So you need to compare sh_name with your required section. On finding required section, you can get its offset(sh_offset) and its size sh_size. Now it is easy for you to get data through loop which reads from sh_offset to sh_offset+sh_offset+sh_size. This is theoretically correct and hope you will get data of required section For further help check following links Get elf sections offsets How to get a pointer to an specific section of a program from within itself? (Maybe with libelf)
You can copy one section of the binary to a text file using the command objcopy from package binutils:
$ objcopy -O binary --only-section=<section> <binary> <output>
So in your case:
$ objcopy -O binary --only-section=.proghead elf-binary-file output.proghead
After that, you can simply code a C++ program that reads a binary file. This approach would work as long as all you need to do is to read that section and not to modify the binary.
If you need to modify the binary, you would need to start reading the section at that sections's offset for size bytes. It's possible to use readelf to know what offset a section starts and its size:
$ readelf --wide -S /bin/ls
There are 28 section headers, starting at offset 0x1c760:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000400238 000238 00001c 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000400254 000254 000020 00 A 0 0 4
[ 3] .note.gnu.build-id NOTE 0000000000400274 000274 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000400298 000298 000068 00 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000400300 000300 000c18 18 A 6 1 8
[ 6] .dynstr STRTAB 0000000000400f18 000f18 000593 00 A 0 0 1
However, bear in mind that directly modifying a binary is fine as long as there's no new data added or data removed. Adding new data, will grow a section which results into overriding data of other sections and disorganizing the section index. Shrinking a section and filling up with padding may be OK but doing in the .text section, for instance, may affect the program's logic if there's a jump to a relative direction that no longer exists.
in general, modify the linker command file to give a name to the first address of the .proghead section.
Then, in the C file write a struct to cover the contents of the .proghead section.
Then set a C pointer variable, of the above struct type, to point to the .proghead section.
From then on, that pointer->fieldName will access each of the fields in the struct that is the .proghead section
Related
I've written a project using C++ to run on ARM Cortex-M (STM32F0) but I had some problems with accessing defined buffers as class members though I resolved that by defining them as global vars.
But now I'm completely stuck with this new problem which I don't know what to do with it.
I've a code to unlock flash and write something into it and close it. If I implement it in C file and run it through C nature (call from main.c) it works perfect. but calling that through C++ files (whether written inside C or C++ source file) it will throw a HardFault Exception.
static uint32_t waitForLastOperation(uint32_t msDelay)
{
while (READ_BIT(FLASH->SR, FLASH_SR_BSY) && msDelay)
{
LL_mDelay(1);
msDelay--;
}
/* Check FLASH End of Operation flag */
if (READ_BIT((FLASH->SR), (FLASH_SR_EOP)))
{
/* Clear FLASH End of Operation pending bit */
(FLASH->SR) = (FLASH_SR_EOP);
}
if (READ_BIT((FLASH->SR),
(FLASH_SR_WRPERR)) || READ_BIT((FLASH->SR), (FLASH_SR_PGERR)))
{
FLASH->SR = 0U;
return 0;
}
/* There is no error flag set */
return 1;
}
uint32_t programHalfWord(uint16_t data, uint32_t address)
{
uint32_t status;
/* Proceed to program the new data */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Write data in the address */
*(__IO uint16_t*) address = data;
/* Wait for last operation to be completed */
status = waitForLastOperation(FLASH_TIMEOUT);
if (READ_BIT(FLASH->SR, FLASH_SR_EOP))
FLASH->SR = FLASH_SR_EOP;
/* If the program operation is completed, disable the PG Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
return status;
}
uint32_t flash_unlock()
{
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) == RESET)
return 1;
/* Authorize the FLASH Registers access */
WRITE_REG(FLASH->KEYR, FLASH_KEY1);
WRITE_REG(FLASH->KEYR, FLASH_KEY2);
/* Verify Flash is unlocked */
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET)
return 0;
return 1;
}
and this is how I use it:
if(flash_unlock())
{
programHalfWord(0x11, 0x8007C00);
}
It throws exception right after executing *(__IO uint16_t*) address = data;.
Flash is erased at this address, address is aligned (it's actually start of a sector). I've checked everything to make sure that flash is unlocked but it seems that there's something with the code compiled in C++.
I'm using arm-none-eabi-gcc and arm-none-eabi-g++ to compile my code.
Thanks in advance
Update:
Here's the list of flags being used with g++ compiler:
-mcpu=cortex-m0 -std=gnu++14 -g3 -DSTM32F030x6 -DHSE_STARTUP_TIMEOUT=100 -DLSE_STARTUP_TIMEOUT=5000 -DDEBUG -DLSE_VALUE=32768 -DDATA_CACHE_ENABLE=0 -DINSTRUCTION_CACHE_ENABLE=0 -DVDD_VALUE=3300 -DLSI_VALUE=40000 -DHSI_VALUE=8000000 -DUSE_FULL_LL_DRIVER -DPREFETCH_ENABLE=1 -DHSE_VALUE=2000000 -c -I../app/Inc -I../Inc -I../Drivers/STM32F0xx_HAL_Driver/Inc -I../Drivers/CMSIS/Include -I../Drivers/CMSIS/Device/ST/STM32F0xx/Include -I../app/Driver -Og -ffunction-sections -fdata-sections -fno-exceptions -fno-rtti -fno-threadsafe-statics -fno-use-cxa-atexit -Wall -fno-short-enums -fstack-usage --specs=nano.specs -mfloat-abi=soft -mthumb
And this is for gcc:
-mcpu=cortex-m0 -std=gnu11 -g3 -DSTM32F030x6 -DHSE_STARTUP_TIMEOUT=100 -DLSE_STARTUP_TIMEOUT=5000 -DDEBUG -DLSE_VALUE=32768 -DDATA_CACHE_ENABLE=0 -DINSTRUCTION_CACHE_ENABLE=0 -DVDD_VALUE=3300 -DLSI_VALUE=40000 -DHSI_VALUE=8000000 -DUSE_FULL_LL_DRIVER -DPREFETCH_ENABLE=1 -DHSE_VALUE=2000000 -c -I../app/Inc -I../Inc -I../Drivers/STM32F0xx_HAL_Driver/Inc -I../Drivers/CMSIS/Include -I../Drivers/CMSIS/Device/ST/STM32F0xx/Include -I../app/Driver -Og -ffunction-sections -fdata-sections -Wall -fno-short-enums -fstack-usage --specs=nano.specs -mfloat-abi=soft -mthumb
and g++ linker:
-mcpu=cortex-m0 -T"./STM32F030K6TX_FLASH.ld" -Wl,-Map="${ProjName}.map" -Wl,--gc-sections -static --specs=nano.specs -mfloat-abi=soft -mthumb -Wl,--start-group -lc -lm -lstdc++ -lsupc++ -Wl,--end-group
Since it is difficult to analyze the issue without having access to your hardware / software setup, I can only make wild guesses and provide some hints, after having some troubles with STM32 flash programming as well recently (on a different STM32 model (STM32F215RET6)). - But I'm not an expert in this area at all, and I've only used the vendor supplied HAL driver to access the internal flash so far.
The error might be caused by a memory bus error.
It would be interesting to verify if that's case with a debugger (e.g. by reading the flash status register (FLASH_SR), right after the error occurred).
The question is: Why does your C code work, when compiled with gcc and why not, when compiled with g++? I guess, it might have something to do with a technical detail, that the compiler "doesn't know" about the underlying restrictions of the architecture / memory model.
The STM32F030K6T reference manual (RM0360) says, in section "3.2.2 Flash program and erase operations, Main Flash memory programming":
The main Flash memory can be programmed 16 bits at a time. The program operation is started when the CPU writes a half-word into a main Flash memory address with the PG bit of the FLASH_CR register set. Any attempt to write data that are not half-word long will result in a bus error generating a Hard Fault interrupt.
So, 32-bit write access to the internal flash will cause a Hard Fault interrupt.
When you compile the project with assembly listing generation enabled, you could analyze what's exactly going in your C++ variant, and compare it to the generated machine code of the C variant.
Since I've been working on a STM32 flash related issue recently as well, I've looked up what's going on in the vendor supplied flash code in my case (stm32f2xx_hal_flash.c), and it turns out, that the main write operation to the flash (*(__IO uint16_t*)Address = Data;) is translated to the matching ARM half-word store instruction strh, like expected:
strh r1, [r0]
This could be verified by looking at the auto-generated assembly listings for the ST supplied FLASH_Program_HalfWord() function in stm32f2xx_hal_flash.c. It looks like that (compiled with GCC with no optimization and debugging information -Og):
662:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** static void FLASH_Program_HalfWord(uint32_t Address, uint16_t Data)
663:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** {
140 .loc 1 663 1 is_stmt 1 view -0
141 .cfi_startproc
142 # args = 0, pretend = 0, frame = 0
143 # frame_needed = 0, uses_anonymous_args = 0
144 # link register save eliminated.
664:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** /* Check the parameters */
665:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** assert_param(IS_FLASH_ADDRESS(Address));
145 .loc 1 665 3 view .LVU27
666:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c ****
667:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** /* If the previous operation is completed, proceed to program the new data */
668:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
146 .loc 1 668 3 view .LVU28
147 0000 074B ldr r3, .L9
148 0002 1A69 ldr r2, [r3, #16]
149 0004 22F44072 bic r2, r2, #768
150 0008 1A61 str r2, [r3, #16]
669:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** FLASH->CR |= FLASH_PSIZE_HALF_WORD;
151 .loc 1 669 3 view .LVU29
152 .loc 1 669 13 is_stmt 0 view .LVU30
153 000a 1A69 ldr r2, [r3, #16]
154 000c 42F48072 orr r2, r2, #256
155 0010 1A61 str r2, [r3, #16]
670:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** FLASH->CR |= FLASH_CR_PG;
156 .loc 1 670 3 is_stmt 1 view .LVU31
157 .loc 1 670 13 is_stmt 0 view .LVU32
158 0012 1A69 ldr r2, [r3, #16]
159 0014 42F00102 orr r2, r2, #1
160 0018 1A61 str r2, [r3, #16]
671:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c ****
672:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** *(__IO uint16_t*)Address = Data;
161 .loc 1 672 3 is_stmt 1 view .LVU33
162 .loc 1 672 28 is_stmt 0 view .LVU34
163 001a 0180 strh r1, [r0] # movhi
673:Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_flash.c **** }
164 .loc 1 673 1 view .LVU35
165 001c 7047 bx lr
166 .L10:
167 001e 00BF .align 2
168 .L9:
169 0020 003C0240 .word 1073888256
170 .cfi_endproc
The generated machine code could be disassembled and inspected with objdump, without all the annotations, like that:
$ arm-none-eabi-objdump -d -j .text.FLASH_Program_HalfWord build/stm32f2xx_hal_flash.o
build/stm32f2xx_hal_flash.o: file format elf32-littlearm
Disassembly of section .text.FLASH_Program_HalfWord:
00000000 <FLASH_Program_HalfWord>:
0: 4b07 ldr r3, [pc, #28] ; (20 <FLASH_Program_HalfWord+0x20>)
2: 691a ldr r2, [r3, #16]
4: f422 7240 bic.w r2, r2, #768 ; 0x300
8: 611a str r2, [r3, #16]
a: 691a ldr r2, [r3, #16]
c: f442 7280 orr.w r2, r2, #256 ; 0x100
10: 611a str r2, [r3, #16]
12: 691a ldr r2, [r3, #16]
14: f042 0201 orr.w r2, r2, #1
18: 611a str r2, [r3, #16]
1a: 8001 strh r1, [r0, #0]
1c: 4770 bx lr
1e: bf00 nop
20: 40023c00 .word 0x40023c00
It would be interesting, if you could find out how it looks like in your object file compiled as C++. Is it also using the strh instruction?
By the way, all the ARM instructions are documented also be ST in the STM32F0xxx Cortex-M0 programming manual (PM0215):
The Cortex-M0 processor implements the ARMv6-M architecture, which is based on the 16-bit Thumb® instruction set and includes Thumb-2 technology.
STRHRt, [Rn, <Rm|#imm>] Store register as halfword
And as a reference, also in the ARM®v6-M Architecture Reference Manual of course.
Side note 1:
The reference manual says that address 0x8007C00 is right at the beginning of flash page 31, in flash sector 7, assuming a STM32F030K6Tx chip is used:
Forgetting about this could cause issues, if the sector is write protected via flash option bytes (but that obviously wasn't the case, since it works fine in the C variant). Just for the sake of completeness (you've already commented on that), a quote from the reference manual, "4.1.3 Write protection option byte":
This set of registers is used to write-protect the Flash memory.
Clearing a bit in WRPx field (and at the same time setting a
corresponding bit in nWRPx field) will write-protect the given memory
sector. For STM32F030x4, STM32F030x6, STM32F070x6, STM32F030x8 and
STM32F070xB devices, WRP bits from 0 to 31 are protecting the
Flash memory by sector of 4 kB.
(Possibly unrelated, but also worth mentioning: beware of the different conditions present when Read Protection (RDP) Level 2 or Level 3 is active. RDP is a different protection mechanism, separate from the sector protection via flash option bytes, or lock state of the flash. Reading the flash from a debugger or when executing form RAM will cause a Hard Fault when RDP Level 2 or 3 is used. Documented in the reference manual, section "3.3.1 Read protection".)
Side note 2:
You could try to mix the official HAL C driver code or your own tested flash related C code, and the new C++ parts of the project, and check if the problem still occurs.
(Be careful when mixing C and C++, and always take care of naming mangeling by using extern "C" { ... }, related post: https://stackoverflow.com/a/1041880/5872574)
Side note 3:
Like already mentioned, I've recently had an unrelated issue with flash programming as well. And saw strange bus errors (in the status register after a Hard Fault). I also made sure that the flash was unlocked, and not write protected. If I remember correctly, I had to add this in front of my erase / write operations (but I do not remember exactly and can't find it right now). It was a necessary but strange fix, because there was no operation in progress, besides regular program execution (from flash).
while (FLASH_WaitForLastOperation(100) != HAL_OK) {
HAL_IWDG_Refresh(&hiwdg);
}
This issue possibly had something to do with the way the STM32 uses the flash with a prefetch buffer / wait states / instruction cache and the data cache like described in the reference manual (see also: FLASH_ACR register). I didn't investigate the issue any further. Just make sure that there is no flash operation pending/active when a write/erase access is initiated.
Also interesting to note, program/erase operations will prevent any read access to the bus (flash memory), but they will not cause an error, like described in the reference manual, in section "3.2.2 Flash program and erase operations":
An ongoing Flash memory operation will not block the CPU as long as
the CPU does not access the Flash memory.
On the contrary, during a program/erase operation to the Flash memory,
any attempt to read the Flash memory will stall the bus. The read
operation will proceed correctly once the program/erase operation has
completed. This means that code or data fetches cannot be made while a
program/erase operation is ongoing.
For program and erase operations on the Flash memory (write/erase),
the internal RC oscillator (HSI) must be ON.
EDIT:
In order to check whether there's really enough flash memory left to write to, and that the area is really unused by the running binary itself, these commands could come in handy, meant as a future reference (using my test binary for an STM32F215RET here):
$ arm-none-eabi-strip build/prj.elf
$ arm-none-eabi-objdump -h build/prj.elf
build/prj.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .isr_vector 00000184 08000000 08000000 00010000 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .text 000134a0 08000188 08000188 00010188 2**3
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rodata 00002968 08013628 08013628 00023628 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .ARM 00000008 08015f90 08015f90 00025f90 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .init_array 00000004 08015f98 08015f98 00025f98 2**2
CONTENTS, ALLOC, LOAD, DATA
5 .fini_array 00000004 08015f9c 08015f9c 00025f9c 2**2
CONTENTS, ALLOC, LOAD, DATA
6 .data 000002c0 20000000 08015fa0 00030000 2**3
CONTENTS, ALLOC, LOAD, DATA
7 .bss 0000149c 200002c0 08016260 000302c0 2**3
ALLOC
8 ._user_heap_stack 00000604 2000175c 08016260 0003175c 2**0
ALLOC
9 .ARM.attributes 00000029 00000000 00000000 000302c0 2**0
CONTENTS, READONLY
10 .comment 0000001e 00000000 00000000 000302e9 2**0
CONTENTS, READONLY
0x08016260 marks the end of the used flash memory by the binary.
That can be verified with arm-none-eabi-size:
$ arm-none-eabi-size build/prj.elf
text data bss dec hex filename
90004 712 6816 97532 17cfc build/prj.elf
$ echo $((90004 + 712))
90716
$ echo $((0x08016260 - 0x08000000 - (90004 + 712)))
4
So, with 2**3 -> 8 byte alignment and a flash base address of 0x08000000, that means that 90720 bytes of flash memory are actually used by the binary.
To find out which of the flash sectors are left unused, it is now easy to look the address up directly in the "Flash memory organization" table in the reference manual.
In my case, the linker script was modified to make sure that only half of the flash is used, like that:
$ cat STM32F215RETx_FLASH.ld
(...)
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K /* keep 256K free at the end */
/* FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K */
}
(...)
That way you'll get a linker error if the binary gets too large.
I had the same issue. My mistake was invalid alignment.
I'm assured 90% of such a errors is alignment issues, especially on Cortex-M0.
I've made proper alignment of my strucrure inside C++ class and it was enough.
Note: functions executed in RAM, like write half page, should better be inside extern "C" {} expression.
I'm trying to get object dump to print the order that static C++ objects are constructed. I found -h for the headers, but I can't seem to get objdump to go any further.
Program compiled without init_priority
$ objdump -h cryptest.exe
cryptest.exe: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001c 0000000000400238 0000000000400238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 0000000000400254 0000000000400254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
...
10 .init 0000001a 000000000040efd8 000000000040efd8 0000efd8 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
...
Program compiled with init_priority
$ objdump -h cryptest.exe
cryptest.exe: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001c 0000000000400238 0000000000400238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 0000000000400254 0000000000400254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
...
10 .init 0000001a 000000000040efd8 000000000040efd8 0000efd8 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
...
19 .init_array 000000a8 00000000008e4008 00000000008e4008 002e4008 2**3
CONTENTS, ALLOC, LOAD, DATA
I'm pretty sure my next step is to inspect .init and .init_array, but I can't seem to get object dump to do it:
$ objdump -d .init cryptest.exe
objdump: '.init': No such file
cryptest.exe: file format elf64-x86-64
...
How do I display the initialization order of static C++ objects in a compiled program?
From How to verify init_priorty for C++ static object initialization order? I know I can get some information about it using objdump -h or readelf -S.
For example, I can see the init_priority value associated with an object file:
$ objdump -h cryptlib.o
509 .init_array.00275 00000008 0000000000000000 0000000000000000 00007da8 2**3
CONTENTS, ALLOC, LOAD, RELOC, DATA
510 .init_array.00276 00000008 0000000000000000 0000000000000000 00007db0 2**3
CONTENTS, ALLOC, LOAD, RELOC, DATA
511 .init_array.00280 00000008 0000000000000000 0000000000000000 00007db8 2**3
Above, I see the init_priority with its value is present in an object file (.init_array.00275), but it does not tell me anything about the variable or the final order once linked into a program.
We recently switched to GCC's init_priority, so I'm trying to add a QA step to ensure the order of the objects are as specified when it in effect. I also want to see the order of the objects when init_priority is not in effect.
This is still a problem for us; since adding new self-tests, we can't get a particular string to initialize at the right time, even with init_priority and laying out object files in the exact order they should be initialized (see How to force the linker to honor object file order?).
There's now an open question on the Binutils mailing list at Display initialization order of static C++ objects in a library or program?
A POD is already initialized in the executable image.
See that .init symbol()? Non-POD static class instances get initialized by a compiler-generated initialization function, that simply invokes every static object's constructor. The .init() function gets invoked when the executable (or the shared object) gets loaded. Its compiler-generated code proceeds to invoke every static object's constructor.
To figure out the initialization order, you'll have to disassemble the .init() function, and figure it out based on that.
I recently faced flash overflow problem. After doing some optimization in code, I saved some flash memory and executed software successfully. I want to how much flash memory is saved through my changes. Please let me know how can I check for used flash / available flash memory. Also I want to how much flash is utilized by particular function/file.
Below mentioned are some info about my developing environment.
- Avr microcontroller with 64 k ram and 512 K flash.
- Using freeRtos.
- Using GNU C++ compiler.
- Using AVRATJTAGEICE for programming and Debugging.
Please let me know the solution.
Regards,
Jagadeep.
GCC's size program is what you're looking for.
size can be passed the full compiled .elf file. It will, by default, output something like this:
$ size linked-file.elf
text data bss dec hex filename
11228 112 1488 12828 321c linked-file.elf
This is saying:
There are 11228 bytes in the .text "section" of this file. This is generally for functions.
There are 112 bytes of initialized data: global variables in the program with initial values.
There are 1488 bytes of uninitialized data: global variables without initial values.
dec is simply the sum of the previous 3 values: 11228 + 112 + 1488 = 12828.
hex is simply the hexadecimal representation of the dec value: 0x321c == 12828.
For embedded systems, generally dec needs to be smaller than the flash size of your target device (or the available space on the device).
It is generally sufficient to simply watch the dec or text outputs of GCC's size command to monitor the size of your compiled code over time. A large jump in size often indicates a poorly implemented new feature or constexpr that are not getting compiled away. (Don't forget function-sections and data-sections).
Note: For AVR's, you'll want to use avr-size for checking the linked size of AVR .elf files. avr-size takes an extra argument of the target chip and will automatically calculate the percentage of used flash for your chosen chip.
GCC's size also works directly on intermediate object files.
This is particularly useful if you want to check the compiled size of functions.
You should see something like this excerpt:
$ size -A main.cpp.o
main.cpp.o :
section size addr
.group 8 0
.group 8 0
.text 0 0
.data 0 0
.bss 0 0
.text._Z8sendByteh 8 0
.text._ZN3XMC5IOpin7setModeENS0_4ModeE 64 0
.text._ZN7NamSpac6OptionIN5Clock4TimeEEmmEi 76 0
.text.Default_Handler 24 0
.text.HardFault_Handler 16 0
.text.SVC_Handler 16 0
.text.PendSV_Handler 16 0
.text.SysTick_Handler 28 0
.text._Z5errorPKc 8 0
.text._ZN7NamSpac5Motor2goEi 368 0
.text._ZN7NamSpac5Motor3getEv 12 0
.rodata.cst1 1 0
.text.startup.main 632 0
.text._ZN7NamSpac7Program3runEv 380 0
.text._ZN7NamSpac8Position4tickEv 24 0
.text.startup._GLOBAL__sub_I__ZN7NamSpac7displayE 292 0
.init_array 4 0
.bss._ZN5Debug9formatterE 4 0
.rodata._ZL10dispDigits 8 0
.bss.position 4 0
.bss.motorState 4 0
.bss.count 4 0
.rodata._ZL9diameters 20 0
.bss._ZN7NamSpac8diameterE 16 0
.bss._ZN5Debug3pinE 12 0
.bss._ZN7NamSpac7displayE 24 0
.rodata.str1.4 153 0
.rodata._ZL12dispSegments 32 0
.bss._ZL16diametersDisplay 10 0
.bss.loadAggregate 4 0
.bss.startCount 4 0
.bss._ZL15runtimesDisplay 10 0
.bss._ZN7NamSpac7runtimeE 16 0
.bss.startTime 4 0
.rodata._ZL8runtimes 20 0
.comment 111 0
.ARM.attributes 49 0
Total 2494
Please let me know the solution.
Sorry, there's no the solution! You've gotta getting through what's linked to your final ELF, and decide if it was linked by intend, or unwanted default.
Please let me know how can I check for used flash / available flash memory.
That primarily depends on your actual target hardware platform, so you have to manage to get your .text section fitting in there.
Also I want to how much flash is utilized by particular function/file.
The nm tool of the GCC binutils provides detailed information about any (global) symbol found in an ELF file and the space it occupies in it's associated section. You'll just need to grep the results for particular functions/classes/namespaces (best demangled!) to accumulate section type and symbol filtered outputs for analysis.
That's the approach, I've been using for a little tool called nmalyzr. Sorry to say, as it stands on the GIT repo, its not really working as intended (I've got working versions, that aren't pushed back).
In general, it's a good strategy to chase for code that has #include <iostream> statements (no matter if std::cout or alike are used or not, static instances are provided!), or unwanted newlib/libstdc++ bindings as for e.g. default exception handling.
Use size command from binutils on the generated elf file. As you seem to use an AVR chip, use avr-size.
To get the size of functions, use nm command from binutils (avr-nm on AVR chips).
Following my question about manually generating a core dump file, I decided to dive into it and get my hands dirty.
I am able to build the basic core dump structure and get my dead program's memory back into the core dump within a big LOAD section. When debugging in GDB, my variables are back, no problem with that.
Here comes the tricky part, how do I get GDB to retrieve information about where the program was when it crashed.
I know that the note section of the core dump contains this information (cpu registers among others). Here is what a objdump -h gives for a "real" core dump :
core.28339: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 note0 000001e8 00000000 00000000 000000f4 2**0
CONTENTS, READONLY
1 .reg/28339 00000044 00000000 00000000 00000150 2**2
CONTENTS
2 .reg 00000044 00000000 00000000 00000150 2**2
CONTENTS
3 .auxv 000000a0 00000000 00000000 0000023c 2**2
CONTENTS
4 load1a 00001000 08010000 00000000 00001000 2**12
CONTENTS, ALLOC, LOAD, READONLY, CODE
.. other load sections ...
I figured out thanks to readelf that those .reg sections contain data mapped from some structures :
Notes at offset 0x000000f4 with length 0x000001e8:
Owner Data size Description
CORE 0x00000090 NT_PRSTATUS (prstatus structure)
CORE 0x0000007c NT_PRPSINFO (prpsinfo structure)
CORE 0x000000a0 NT_AUXV (auxiliary vector)
Can someone give me directions on how is structured the Notes section ?
I tried writing directly those structures to my file, it did not work and I am obviously missing something here.
I looked at the Google Coredumper code and took some bits of it, but writing the note section is not that simple and any detailed information about what it exactly contains and its format are welcomed.
Edit #1 : following 1st comment
I figured out my Elf file should be structured as follows :
Elf header ElfW(Ehdr)
Program headers (Ehdr.e_phnum times ElfW(Phdr)), here i basically used one PT_NOTE and one PT_LOAD headers
Note sections :
Section's header (ElfW(Nhdr))
Section's name (.n_namesz long)
Section's data (.n_descsz long)
Program section containing all my program's memory
Then i will have to put 3 note records, one for the prstatus, one for prpsinfo and one for the auxiliary vector.
This seems to be the right way as readelf gives me a similar output as what I got above with the real core dump.
Edit #2 : after getting the correct structure
I am now struggling with the different structures composing the note records.
Here is what I get when running a eu-readelf --notes on my core dump :
Note segment of 540 bytes at offset 0x74:
Owner Data size Type
CORE 336 PRSTATUS
CORE 136 PRPSINFO
CORE 8 AUXV
NULL
Here is what I get when running the same command on the real core dump :
Note segment of 488 bytes at offset 0xf4:
Owner Data size Type
CORE 144 PRSTATUS
info.si_signo: 11, info.si_code: 0, info.si_errno: 0, cursig: 11
sigpend: <>
sighold: <>
pid: 28339, ppid: 41446, pgrp: 28339, sid: 41446
utime: 0.000000, stime: 0.000000, cutime: 0.000000, cstime: 0.000000
orig_eax: -1, fpvalid: 0
ebx: -1 ecx: 0 edx: 0
esi: 0 edi: 0 ebp: 0xffb9fcbc
eax: -1 eip: 0x08014b26 eflags: 0x00010286
esp: 0xffb9fcb4
ds: 0x002b es: 0x002b fs: 0x0000 gs: 0x0000 cs: 0x0023 ss: 0x002b
CORE 124 PRPSINFO
state: 0, sname: R, zomb: 0, nice: 0, flag: 0x00400400
uid: 9432, gid: 6246, pid: 28339, ppid: 41446, pgrp: 28339, sid: 41446
fname: pikeos_app, psargs: ./pikeos_app
CORE 160 AUXV
SYSINFO: 0xf7768420
SYSINFO_EHDR: 0xf7768000
HWCAP: 0xbfebfbff <fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe>
PAGESZ: 4096
CLKTCK: 100
PHDR: 0x8010034
PHENT: 32
PHNUM: 2
BASE: 0
FLAGS: 0
ENTRY: 0x80100be
UID: 9432
EUID: 9432
GID: 6246
EGID: 6246
SECURE: 0
RANDOM: 0xffb9ffab
EXECFN: 0xffba1feb
PLATFORM: 0xffb9ffbb
NULL
Does someone have any clue or explanations about why my note records are not read properly ?
I thought it might be due to incorrect offsets, but then why would the records be correctly listed ?
Thanks !
Was having same troubles some time ago with my project of converting CRIU images into core dumps. It is fully written in python(even elf structures are in ctypes), so it could be used as a guide. See https://github.com/efiop/criu-coredump .I.e. how everything is structured could be seen here https://github.com/efiop/criu-coredump/blob/master/criu_coredump/core_dump.py .
Can someone give me directions on how is structured the Notes section?
The notes section is a concatenation of variable-sized note records. Each note record begins with ElfW(Nhdr) structure, followed by (variable sized) name (of length .n_namesz, padded so total size of name on disk is divisible by 4) and data (of length .n_descsz, similarly padded).
After some tests I figured things out, answering for anyone looking for this information :
Can someone confirm I am going the right way structuring my Elf file this way ?
Yes.
As GDB is accepting the file, this seems to be the right way of doing. Results shown by readelf -a show the correct structure, good so far.
I am not sure about where should lay the data (note & program sections) into my file : is there a mandatory order, or is this my program headers offset that define where the data is ?
Offsets given to Phdr.p_offset should point where the data lays in the Elf file. They start at the very beginning of the file.
For example :
The p_offset for the PT_NOTE program header should be set at sizeof(ElfW(Ehdr)) + ehdr.e_phnum*sizeof(ElfW(Phdr)). ehdr.e_phnum being the number of program header present in the Elf file.
For the PT_LOAD program header, this is a bit longer, cause we will also have to add length of all the note sections. For a "standard" core dump with a note segment containg NT_PRSTATUS, NT_PRPSINFO and NT_AUXV sections, offset for the PT_LOAD data (Phdr.p_offset) will be :
sizeof(ElfW(Ehdr)) + ehdr.e_phnum*sizeof(ElfW(Phdr))
+ sizeof(ElfW(Nhdr)) + sizeof(name_of_section) + sizeof(struct prstatus)
+ sizeof(ElfW(Nhdr)) + sizeof(name_of_section) + sizeof(struct prpsinfo)
+ sizeof(ElfW(Nhdr)) + sizeof(name_of_section) + sizeof(struct auxv_t)
I copied a FORTRAN IV program from a thesis, so it presumably worked at the time it was written. I compiled it with gfortran. When running, it stalls in an integration subroutine. I have tried easing off the residuals but to no avail. I am asking for help because (presuming no mistakes in code) gfortran might not like the archaic 66/IV code, and updating it is outside my abilities.
The program gets stuck by line 9, so I wonder if the DO loops are responsible. Note, lines 1 and 6 are unusual to me because ',1' has been added to the ends: e.g. =1,N,1.
I don't think it's necessary to show the FUNC subroutine called on line 5 but am happy to provide it if necessary.
If you need more detailed information I am happy to provide it.
00000001 13 DO 22 TDP=QDP,7,1
00000002 TD=TDP-1
00000003 X=X0+H0
00000004 IF(TD.EQ.QD) GOTO 15
00000005 CALL FUNC(N,DY,X,Y,J)
00000006 15 DO 21 RD=1,N,1
00000007 GOTO (120,121,122,123,124,125,126),TDP
00000008 120 RK(5*N*RD)=Y(RD)
00000009 GOTO 21
00000010 121 RK(RD)=HD*DY(RD)
00000011 H0=0.5*HD
00000012 F0=0.5*RK(RD)
00000013 GOTO 20
00000014 122 RK(N+RD)=HD*DY(RD)
00000015 F0=0.25*(RK(RD)+RK(N+RD))
00000016 GOTO 20
00000017 123 RK(2*N+RD)=HD*DY(RD)
00000018 H0=HD
00000019 F0=-RK(N+RD)+2.*RK(2*N+RD)
00000020 GOTO 20
00000021 124 RK(3*N+RD)=HD*DY(RD)
00000022 H0=0.66666666667*HD
00000023 F0=(7.*RK(RD)+10.*RK(N+RD)+RK(3*N+RD))/27.
00000024 GOTO 20
00000025 125 RK(4*N+RD)=HD*DY(RD)
00000026 H0=0.2*HD
00000027 F0=(28.*RK(RD)-125.*RK(N+RD)+546.*RK(2*N+RD)+54.*RK(3*N+RD)-
00000028 1378.*RK(4*N+RD))/625.
00000029 GOTO 20
00000030 126 RK(6*N+RD)=HD*DY(RD)
00000031 F0=0.1666666667*(RK(RD)+4.*RK(2*N+RD)+RK(3*N+RD))
00000032 X=X0+HD
00000033 ER=(-42.*RK(RD)-224.*RK(2*N+RD)-21.*RK(3*N+RD)+162.*RK(4*N+RD)
00000034 1+125.*RK(6*N+RD))/67.2
00000035 YN=RK(5*N+RD)+F0
00000036 IF(ABS(YN).LT.1E-8) YN=1
00000037 ER=ABS(ER/YN)
00000038 IF(ER.GT.G0) GOTO 115
00000039 IF(ED.GT.ER) GOTO 20
00000040 QD=-1
00000041 20 Y(RD)=RK(5*N+RD)+F0
00000042 21 CONTINUE
00000043 22 CONTINUE
It's difficult to be certain (not entirely sure your snippet exactly matches your source file) but your problem might arise from an old FORTRAN gotcha -- a 0 in column 6 is (or rather was) treated as a blank. Any other (non-blank) character in column 6 is/was treated as a continuation indicator, but not the 0.
Not all f66 compilers adhered to the convention of executing a loop at least once, but it was a common (non-portable) assumption.
Similarly, the assumption of all static variables was not a portable one, but can be implemented by adding a SAVE statement, beginning with f77. A further assumption that SAVE variables will be zero-initialized is even more non-portable, but most compilers have an option to implement that.
If an attempt is being made to resurrect old code, it is probably worth while to get it working before modernizing it incrementally so as to make it more self-documenting. The computed goto looks like a relatively sane one which could be replaced by select case, at a possible expense of optimization. Here the recent uses of the term "modernization" become contradictory.
The ,1 bits are to get the compiler to spot the errors. It is quite common to do the following
DO 10 I = 1.7
That is perfectly legal since spaces are allowed in variable names. If you wish to avoid that, then put in the extra number. The following will generate errors
DO 10 I = 1.7,1
DO 10 I = 1,7.1
DO 10 I = 1.7.1
Re the program getting struck, try puting a continuation line between labels 21 and 22. The if-goto is the same as if-not-then in the later versions of Fortran and the computed goto is the same as a select statement. You don't need to recode it: there is nothing wrong with it other than youngsters getting confused whenever they see goto. All you need to do is indent it and it becomes obvious. So what you will have is
DO 22 TDP = QDP, 7, 1
...
DO 23 RD = 1, N, 1
GOTO (...) TDP
...
GOTO 21
...
GOTO 20
...
GOTO 20
...
20 CONTINUE
Y(RD) = ...
21 CONTINUE
23 CONTINUE
22 CONTINUE
You will probably end up with far more code if you try recoding it. It will look exactly the same except that gotos have been replaced by other words. It is possible that the compiler is generating the wrong code so just help it by putting a few dummy (CONTINUE) statements.