I have an STM32 project involving a linkerscript which is designed to cap off the end of the image with a ".firmware_header" section. The idea is that this header contains the crc of the image, and there should be no content after this point. However, when I do
arm-none-eabi-objcopy firmware.elf -O binary firmware.bin
there exists some data after the last section which for some reason is required for the image to boot. If I zero this mystery block, the image fails to boot. The first question is, from the elf sections I see, there should be no sections after .firmware_header, where is the data coming from? The second question is, why is this data required at boot? My linker script, readelf output, and a screenshot of the mystery data is below.
ENTRY(Reset_Handler)
MEMORY
{
FLASH (RX) : ORIGIN = 0x08020000, LENGTH = 896K
SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 512K
BKPSRAM (RW) : ORIGIN = 0x40024000, LENGTH = 4K
}
_estack = 0x20080000;
SECTIONS
{
.isr_vector :
{
. = ALIGN(4);
_isr_vector = .;
KEEP(*(.isr_vector))
. = ALIGN(4);
} > FLASH
.firmware_header_vector :
{
. = ALIGN(4);
KEEP(*(.firmware_header_vector))
. = ALIGN(4);
} > FLASH
.text :
{
. = ALIGN(4);
_stext = .;
*(.Reset_Handler)
*(.text)
*(.text*)
*(.rodata)
*(.rodata*)
*(.glue_7)
*(.glue_7t)
KEEP(*(.init))
KEEP(*(.fini))
. = ALIGN(4);
_etext = .;
} > FLASH
.ARM.extab :
{
. = ALIGN(4);
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
. = ALIGN(4);
} > FLASH
.exidx :
{
. = ALIGN(4);
PROVIDE(__exidx_start = .);
*(.ARM.exidx*)
. = ALIGN(4);
PROVIDE(__exidx_end = .);
} > FLASH
.preinit_array :
{
PROVIDE(__preinit_array_start = .);
KEEP(*(.preinit_array*))
PROVIDE(__preinit_array_end = .);
} > FLASH
.init_array :
{
PROVIDE(__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array*))
PROVIDE(__init_array_end = .);
} > FLASH
.fini_array :
{
PROVIDE(__fini_array_start = .);
KEEP(*(.fini_array*))
KEEP(*(SORT(.fini_array.*)))
PROVIDE(__fini_array_end = .);
} > FLASH
.firmware_header :
{
. = ALIGN(4);
KEEP(*(.firmware_header))
. = ALIGN(4);
} > FLASH
. = ALIGN(4);
_sidata = .;
.data : AT(_sidata)
{
. = ALIGN(4);
_sdata = .;
PROVIDE(__data_start__ = _sdata);
*(.data)
*(.data*)
. = ALIGN(4);
_edata = .;
PROVIDE(__data_end__ = _edata);
} > SRAM
.bss :
{
. = ALIGN(4);
_sbss = .;
PROVIDE(__bss_start__ = _sbss);
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
PROVIDE(__bss_end__ = _ebss);
} > SRAM
PROVIDE(end = .);
.heap (NOLOAD) :
{
. = ALIGN(4);
PROVIDE(__heap_start__ = .);
KEEP(*(.heap))
. = ALIGN(4);
PROVIDE(__heap_end__ = .);
} > SRAM
.reserved_for_stack (NOLOAD) :
{
. = ALIGN(4);
PROVIDE(__reserved_for_stack_start__ = .);
KEEP(*(.reserved_for_stack))
. = ALIGN(4);
PROVIDE(__reserved_for_stack_end__ = .);
} > SRAM
.battery_backed_sram (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.battery_backed_sram))
. = ALIGN(4);
} > BKPSRAM
/DISCARD/ :
{
*(.ARM.attributes)
}
}
arm-none-eabi-readelf -a ./fw.elf:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x8027c11
Start of program headers: 52 (bytes into file)
Start of section headers: 339928 (bytes into file)
Flags: 0x5000400, Version5 EABI, hard-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 3
Size of section headers: 40 (bytes)
Number of section headers: 25
Section header string table index: 24
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .isr_vector PROGBITS 08020000 010000 0001f8 00 WA 0 0 4
[ 2] .firmware_header_ PROGBITS 080201f8 0101f8 000004 00 WA 0 0 4
[ 3] .text PROGBITS 08020200 010200 021b44 00 AX 0 0 64
[ 4] .ARM.extab PROGBITS 08041d44 043a68 000000 00 W 0 0 1
[ 5] .exidx ARM_EXIDX 08041d44 031d44 000008 00 AL 3 0 4
[ 6] .init_array INIT_ARRAY 08041d4c 031d4c 000008 04 WA 0 0 4
[ 7] .fini_array FINI_ARRAY 08041d54 031d54 000004 04 WA 0 0 4
[ 8] .firmware_header PROGBITS 08041d58 031d58 000008 00 WA 0 0 4
[ 9] .data PROGBITS 20000000 040000 0009c8 00 WA 0 0 8
[10] .RxDecripSection PROGBITS 200009c8 0409c8 000080 00 WA 0 0 4
[11] .RxarraySection PROGBITS 20000a48 040a48 0017d0 00 WA 0 0 4
[12] .TxDescripSection PROGBITS 20002218 042218 000080 00 WA 0 0 4
[13] .TxarraySection PROGBITS 20002298 042298 0017d0 00 WA 0 0 4
[14] .bss NOBITS 20003a68 043a68 045da4 00 WA 0 0 4
[15] .heap PROGBITS 2004980c 043a68 000000 00 W 0 0 1
[16] .reserved_for_sta PROGBITS 2004980c 043a68 000000 00 W 0 0 1
[17] .battery_backed_s NOBITS 40024000 044000 00000c 00 WA 0 0 4
[18] .comment PROGBITS 00000000 043a68 000075 01 MS 0 0 1
[19] .debug_frame PROGBITS 00000000 043ae0 00144c 00 0 0 4
[20] .stab PROGBITS 00000000 044f2c 000084 0c 21 0 4
[21] .stabstr STRTAB 00000000 044fb0 000117 00 0 0 1
[22] .symtab SYMTAB 00000000 0450c8 009b30 10 23 1790 4
[23] .strtab STRTAB 00000000 04ebf8 0042bb 00 0 0 1
[24] .shstrtab STRTAB 00000000 052eb3 000122 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
y (purecode), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x08020000 0x08020000 0x21d60 0x21d60 RWE 0x10000
LOAD 0x040000 0x20000000 0x08041d60 0x03a68 0x4980c RW 0x10000
LOAD 0x044000 0x40024000 0x40024000 0x00000 0x0000c RW 0x10000
Turns out this is an issue with the definition of the .data section. It's getting loaded after .firmware_header. Interesting that this wasn't made more clear in readefl, etc output. Solved!
Related
Any experts with a deep understanding of ELF loading, could you please explain to me why the following ELF file throws a Segmentation fault (errno=139)?
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x131a
Start of program headers: 64 (bytes into file)
Start of section headers: 232 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 64 (bytes)
Number of section headers: 8
Section header string table index: 7
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] null NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .init PROGBITS 000000000000131a 0000031a
0000000000000001 0000000000000000 AX 0 0 1
[ 2] .text PROGBITS 000000000000131b 0000031b
0000000000000096 0000000000000000 AX 0 0 1
[ 3] .fini PROGBITS 00000000000013b1 000003b1
0000000000000001 0000000000000000 AX 0 0 1
[ 4] .rodata PROGBITS 00000000000013b2 000003b2
0000000000000014 0000000000000000 A 0 0 1
[ 5] .data PROGBITS 00000000000013c6 000003c6
000000000000001e 0000000000000000 A 0 0 1
[ 6] .bss NOBITS 00000000000013e4 000003e4
0000000000000000 0000000000000000 WA 0 0 1
[ 7] strtab STRTAB 00000000000012e8 000002e8
0000000000000032 0000000000000000 AS 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x000000000000031a 0x000000000000131a 0x000000000000131a
0x0000000000000098 0x0000000000000098 R E 0x1000
LOAD 0x00000000000003b2 0x00000000000013b2 0x00000000000013b2
0x0000000000000014 0x0000000000000014 R 0x1000
LOAD 0x00000000000003c6 0x00000000000013c6 0x00000000000013c6
0x000000000000001e 0x000000000000101e RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .init .text .fini
01 .rodata
02 .data .bss
The exact same executable with the following file alignment changes works fine:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x10400
Start of program headers: 64 (bytes into file)
Start of section headers: 232 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 64 (bytes)
Number of section headers: 8
Section header string table index: 7
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] null NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .init PROGBITS 0000000000010400 00000400
0000000000000001 0000000000000000 AX 0 0 1
[ 2] .text PROGBITS 0000000000010800 00000800
0000000000000096 0000000000000000 AX 0 0 1
[ 3] .fini PROGBITS 0000000000010c00 00000c00
0000000000000001 0000000000000000 AX 0 0 1
[ 4] .rodata PROGBITS 0000000000011000 00001000
0000000000000014 0000000000000000 A 0 0 1
[ 5] .data PROGBITS 0000000000011400 00001400
000000000000001e 0000000000000000 A 0 0 1
[ 6] .bss NOBITS 0000000000011800 00001800
0000000000000000 0000000000000000 WA 0 0 1
[ 7] strtab STRTAB 00000000000102e8 000002e8
0000000000000032 0000000000000000 AS 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000400 0x0000000000010400 0x0000000000010400
0x0000000000000801 0x0000000000000801 R E 0x1
LOAD 0x0000000000001000 0x0000000000011000 0x0000000000011000
0x0000000000000014 0x0000000000000014 R 0x1
LOAD 0x0000000000001400 0x0000000000011400 0x0000000000011400
0x000000000000001e 0x000000000000101e RW 0x1
Section to Segment mapping:
Segment Sections...
00 .init .text .fini
01 .rodata
02 .data .bss
In both cases it holds that:
sh_addr mod sh_addralign = 0 and
p_vaddr mod PAGESIZE = p_offset. (Pagesize acquired with getconf PAGESIZE).
I appreciate your help - thank you very much in advance.
UPDATE:
I realized that my LOAD segments were overlapping in virtual memory in the first readelf printout that I posted. I have corrected this now, but for the now non-overlapping LOAD segments I still get a segmentation fault when my start virtual memory address for the first page is at 0x0 (same if it is at 0x1000, i.e. one page size higher):
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x31a
Start of program headers: 64 (bytes into file)
Start of section headers: 232 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 64 (bytes)
Number of section headers: 8
Section header string table index: 7
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] null NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .init PROGBITS 000000000000031a 0000031a
0000000000000001 0000000000000000 AX 0 0 0
[ 2] .text PROGBITS 000000000000031b 0000031b
0000000000000076 0000000000000000 AX 0 0 0
[ 3] .fini PROGBITS 0000000000000391 00000391
0000000000000001 0000000000000000 AX 0 0 0
[ 4] .rodata PROGBITS 0000000000001392 00000392
0000000000000014 0000000000000000 A 0 0 0
[ 5] .data PROGBITS 00000000000023a6 000003a6
000000000000001e 0000000000000000 A 0 0 0
[ 6] .bss NOBITS 00000000000023c4 000003c4
0000000000000000 0000000000000000 WA 0 0 0
[ 7] strtab STRTAB 00000000000002e8 000002e8
0000000000000032 0000000000000000 AS 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x000000000000031a 0x000000000000031a 0x000000000000031a
0x0000000000000078 0x0000000000000078 R E 0x1000
LOAD 0x0000000000000392 0x0000000000001392 0x0000000000001392
0x0000000000000014 0x0000000000000014 R 0x1000
LOAD 0x00000000000003a6 0x00000000000023a6 0x00000000000023a6
0x000000000000001e 0x0000000000000082 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .init .text .fini
01 .rodata
02 .data .bss
When I change the start address to 0x10000 (PAGESIZE * 16), then the segmentation fault disappears. Any ideas why that is?
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1031a
Start of program headers: 64 (bytes into file)
Start of section headers: 232 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 64 (bytes)
Number of section headers: 8
Section header string table index: 7
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] null NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .init PROGBITS 000000000001031a 0000031a
0000000000000001 0000000000000000 AX 0 0 0
[ 2] .text PROGBITS 000000000001031b 0000031b
0000000000000076 0000000000000000 AX 0 0 0
[ 3] .fini PROGBITS 0000000000010391 00000391
0000000000000001 0000000000000000 AX 0 0 0
[ 4] .rodata PROGBITS 0000000000011392 00000392
0000000000000014 0000000000000000 A 0 0 0
[ 5] .data PROGBITS 00000000000123a6 000003a6
000000000000001e 0000000000000000 A 0 0 0
[ 6] .bss NOBITS 00000000000123c4 000003c4
0000000000000000 0000000000000000 WA 0 0 0
[ 7] strtab STRTAB 00000000000002e8 000002e8
0000000000000032 0000000000000000 AS 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x000000000000031a 0x000000000001031a 0x000000000001031a
0x0000000000000078 0x0000000000000078 R E 0x1000
LOAD 0x0000000000000392 0x0000000000011392 0x0000000000011392
0x0000000000000014 0x0000000000000014 R 0x1000
LOAD 0x00000000000003a6 0x00000000000123a6 0x00000000000123a6
0x000000000000001e 0x0000000000000082 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .init .text .fini
01 .rodata
02 .data .bss
UPDATE 2:
Thank you Employed Russian for your answer and ideas. I wanted to share the following update on my own research:
After digging a bit more, I ran across the following line in an Oracle document about program loading:
By default, 64–bit SPARC programs are linked with a starting address of 0x100000000. The whole program is located above 4 gigabytes, including its text, data, heap, stack, and shared object dependencies. This helps ensure that 64–bit programs are correct because the program will fault in the least significant 4 gigabytes of its address space if the program truncates any of its pointers. While 64–bit programs are linked above 4 gigabytes, you can still link programs below 4 gigabytes by using a mapfile and the -M option to the link-editor. See /usr/lib/ld/sparcv9/map.below4G.
(Source: https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-34713/index.html)
Now I am aware the information from that link is awfully specific, but I was nonetheless wondering if there could be some more universal truth to this on other platforms, or at least point me in the right direction.
So I wrote a tiny test program in C and compiled it in two different ways:
gcc test.c - ELF type is ET_DYN / shared object file and no default virtual address offset is used for the LOAD segments:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0005c8 0x0005c8 R 0x1000
LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x0001c5 0x0001c5 R E 0x1000
LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000130 0x000130 R 0x1000
LOAD 0x002df0 0x0000000000003df0 0x0000000000003df0 0x000220 0x000228 RW 0x1000
gcc -static test.c - ELF type is ET_EXEC / executable and default virtual address offset of 0x400000 is used:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x000518 0x000518 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x0936dd 0x0936dd R E 0x1000
LOAD 0x095000 0x0000000000495000 0x0000000000495000 0x02664d 0x02664d R 0x1000
LOAD 0x0bc0c0 0x00000000004bd0c0 0x00000000004bd0c0 0x005170 0x0068c0 RW 0x1000
Any ideas why that is? I know it possibly has to do with position-independent code, but I do not understand the necessity for an offset if absolute code is used (as in 2. above). Thanks.
When I change the start address to 0x10000 (PAGESIZE * 16), then the segmentation fault disappears. Any ideas why that is?
This was mentioned in the comments to this answer:
Why does loading at 0x10000 work but at 0x1000 doesn't? Does this depend on the kernel or the hardware? How do I pick the right number here?
Some code in the kernel doesn't like to use addresses below 0x10000, but I have not found that code.
I've tried to load a binary with first PT_LOAD.p_vaddr == 0x1000 into UML kernel (which is easy to debug), but that actually worked, so specific kernel code which prohibits this may be architecture-dependent.
I'd like to use the bpftool prog load to load my program into kernel. However, some errors occurred.
# bpftool prog load sockmap_update_kern.o "/sys/fs/bpf/bpf_sockmap"
libbpf: sec 'sockops': failed to find program symbol at offset 0
Error: failed to open object file
The program compiles fine with LLVM version 6.0.0
#include <linux/bpf.h>
#include "bpf_helpers.h"
struct bpf_map_def SEC("maps") sock_map = {
.type = BPF_MAP_TYPE_SOCKMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 10,
};
SEC("sockops")
int sock_map_update(struct bpf_sock_ops *ops)
{
__u32 op, family;
int key;
op = ops->op;
family = ops->family;
switch (op){
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
if (family == 2){ //AF_INET
key = 1;
bpf_sock_map_update(ops, &sock_map, &key, BPF_ANY);
}
default:
break;
}
return 0;
}
char _license[] SEC("license") = "GPL";
# readelf -a sockmap_update_kern.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Linux BPF
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 456 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 8
Section header string table index: 1
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .strtab STRTAB 0000000000000000 00000170
0000000000000051 0000000000000000 0 0 1
[ 2] .text PROGBITS 0000000000000000 00000040
0000000000000000 0000000000000000 AX 0 0 4
[ 3] sockops PROGBITS 0000000000000000 00000040
0000000000000088 0000000000000000 AX 0 0 8
[ 4] .relsockops REL 0000000000000000 00000160
0000000000000010 0000000000000010 7 3 8
[ 5] maps PROGBITS 0000000000000000 000000c8
000000000000001c 0000000000000000 WA 0 0 4
[ 6] license PROGBITS 0000000000000000 000000e4
0000000000000004 0000000000000000 WA 0 0 1
[ 7] .symtab SYMTAB 0000000000000000 000000e8
0000000000000078 0000000000000018 1 2 8
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There is no dynamic section in this file.
Relocation section '.relsockops' at offset 0x160 contains 1 entry:
Offset Info Type Sym. Value Sym. Name
000000000058 000300000001 unrecognized: 1 0000000000000000 sock_map
The decoding of unwind sections for machine type Linux BPF is not currently supported.
Symbol table '.symtab' contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000078 0 NOTYPE LOCAL DEFAULT 3 LBB0_3
2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 6 _license
3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 5 sock_map
4: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 3 sock_map_update
No version information found in this file.
My kernel version is 5.3.0-42. I get it by apt-get install, so I guess there are some problems about the kernel. Could you give me some advise? Thanks in advance.
# uname -a
Linux iZ2zehe0r5ccv5sse5ib5fZ 5.3.0-42-generic #34~18.04.1-Ubuntu SMP Fri Feb 28 13:42:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
I'm working on a project which involves parsing an arm elf file and extracting the sections from it.
There are obviously plenty of sections in an elf file which do not get loaded into flash, but I'm wondering how exactly objcopy knows which sections to include in a binary to be flashed directly into flash?
Take for example the following readelf of an arm elf file:
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .isr_vector PROGBITS 08020000 010000 0001f8 00 WA 0 0 4
[ 2] .firmware_header_ PROGBITS 080201f8 0101f8 000004 00 WA 0 0 4
[ 3] .text PROGBITS 08020200 010200 01e11c 00 AX 0 0 64
[ 4] .ARM.extab PROGBITS 0803e31c 033a68 000000 00 W 0 0 1
[ 5] .exidx ARM_EXIDX 0803e31c 02e31c 000008 00 AL 3 0 4
[ 6] .ARM.attributes ARM_ATTRIBUTES 0803e324 033a68 000030 00 0 0 1
[ 7] .init_array INIT_ARRAY 0803e324 02e324 000008 04 WA 0 0 4
[ 8] .fini_array FINI_ARRAY 0803e32c 02e32c 000004 04 WA 0 0 4
[ 9] .firmware_header PROGBITS 0803e330 02e330 000008 00 WA 0 0 4
[10] .data PROGBITS 20000000 030000 0009c8 00 WA 0 0 8
[11] .RxDecripSection PROGBITS 200009c8 0309c8 000080 00 WA 0 0 4
[12] .RxarraySection PROGBITS 20000a48 030a48 0017d0 00 WA 0 0 4
[13] .TxDescripSection PROGBITS 20002218 032218 000080 00 WA 0 0 4
[14] .TxarraySection PROGBITS 20002298 032298 0017d0 00 WA 0 0 4
[15] .bss NOBITS 20003a68 033a68 045bc0 00 WA 0 0 8
[16] .heap PROGBITS 20049628 033a98 000000 00 W 0 0 1
[17] .reserved_for_sta PROGBITS 20049628 033a98 000000 00 W 0 0 1
[18] .battery_backed_s NOBITS 40024000 034000 00000c 00 WA 0 0 4
[19] .comment PROGBITS 00000000 033a98 000075 01 MS 0 0 1
[20] .debug_frame PROGBITS 00000000 033b10 001404 00 0 0 4
[21] .stab PROGBITS 00000000 034f14 000084 0c 22 0 4
[22] .stabstr STRTAB 00000000 034f98 000117 00 0 0 1
[23] .symtab SYMTAB 00000000 0350b0 009010 10 24 1646 4
[24] .strtab STRTAB 00000000 03e0c0 003dc8 00 0 0 1
[25] .shstrtab STRTAB 00000000 041e88 000132 00 0 0 1
Now, obviously quite a few of these sections (like .TxarraySection) are not loaded into flash. However, that section type is PROGBITS and it has a writable and allocated flag. This is no different than isr_vector, which is loaded but has the same type and flags. What am I missing here? Should I be looking in the program header?
How sure are you that TxarraySection isn't resident in flash? My guess is that it is, but your system initialization ignores it on startup.
Here's what the objcopy man page has to say about what it's doing:
objcopy can be used to generate a raw binary file by using an output target of ‘binary’ (e.g., use -O binary). When objcopy generates a raw binary file, it will essentially produce a memory dump of the contents of the input object file. All symbols and relocation information will be discarded. The memory dump will start at the load address of the lowest section copied into the output file.
I have my own Cortex-M7 elf file that I used to test this. I can convert to binary using objcopy probably the same way you are:
objcopy -O binary in.axf out.bin
In my case the size of out.bin is 376480. I can then inspect the input ELF file using readelf probably the same way you are:
readelf -S in.axf
I get a list of sections similar to the ones you've shown. If I then go through and add up the sizes of everything that is of type PROGBITS which also includes an Alloc flag, it adds up to exactly 376480. As described, objcopy has simply gone through the list of allocated sections in order and copied them to the output.
In general objcopy is pretty "dumb" in the sense that it doesn't try to make any sophisticated decisions about what to include or exclude. There are flags you can use to explicitly include or exclude certain regions, but in general if you're working on a bare-metal platform, it's up to you to decide exactly how your flash image should be laid out.
Without knowing all of the details of your particular system it's very hard to know exactly how to answer your question, but the most important detail to highlight is that objcopy doesn't really know anything, it will blindly copy just about anything, which means in most cases if you're just using -O binary with no other guidance, you're probably ending up with junk in your flash image that you don't actually need or want.
The sections copied to binary are those with a nonzero size, containing the SHF_ALLOC flag, with a type not equal to NOBITS.
The address tells you that it's in RAM, so unless your flash programmer can also handle SRAM, you can eliminate them that way. Ditto that's how you can handle debug symbols too, their addresses are zero.
I have this linker script for my elf executable:
ENTRY(_start)
SECTIONS
{
. = 0x500;
.mboot BLOCK(4K) : ALIGN(4K)
{
*(.mboot)
}
. = 0x7E00;
.ap_stack BLOCK(48K) : ALIGN(4K)
{
*(.ap_stack)
}
.mp_entry BLOCK(4K) : ALIGN(4K)
{
*(.mp_entry)
}
_mp_entry_end = .;
. = 1M;
.init BLOCK(4K) : ALIGN(4K)
{
*(.init)
}
_init_end = .;
. = 0xFFFFFFFF80000000 + _init_end;
.text : AT(ADDR(.text) - 0xFFFFFFFF80000000)
{
_code = .;
*(.text)
*(.rodata*)
*(.stack)
. = ALIGN(4096);
}
.data : AT(ADDR(.data) - 0xFFFFFFFF80000000)
{
_data = .;
*(.data)
. = ALIGN(4096);
}
.eh_frame : AT(ADDR(.eh_frame) - 0xFFFFFFFF80000000)
{
_ehframe = .;
*(.eh_frame)
. = ALIGN(4096);
}
.bss : AT(ADDR(.bss) - 0xFFFFFFFF80000000)
{
_bss = .;
*(.bss)
*(.rodata)
*(COMMON)
. = ALIGN(4096);
}
_end = .;
/DISCARD/ :
{
*(.comment)
}
}
Which should place section .ap_stack at physical/virtual address 0x8000. In assembly, I have:
[BITS 32]
section .ap_stack, nobits
align 16
ap_stack:
resb 0x48000
ap_stack_top:
which should make an empty space at that point, however, if I check final elf, I get:
Idx Name Size VMA LMA File off Algn
0 .mboot 0000000c 0000000000001000 0000000000001000 00001000 2**12
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .mp_entry 00000001 000000000000c000 000000000000c000 00002000 2**12
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .init 00006054 0000000000100000 0000000000100000 00003000 2**12
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .text 0000efa0 ffffffff80106060 0000000000106060 00009060 2**5
CONTENTS, ALLOC, LOAD, READONLY, CODE
4 .data 00001000 ffffffff80115000 0000000000115000 00018000 2**5
CONTENTS, ALLOC, LOAD, DATA
5 .eh_frame 00002000 ffffffff80116000 0000000000116000 00019000 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .bss 00012000 ffffffff80118000 0000000000118000 0001b000 2**5
ALLOC
7 .stack, 00005000 ffffffff8012a000 000000000012a000 0001b000 2**4
ALLOC, READONLY
8 .ap_stack, 00048000 ffffffff8012f000 000000000012f000 0001b000 2**4
ALLOC, READONLY
9 .debug_info 000097b8 0000000000000000 0000000000000000 0001b000 2**0
CONTENTS, READONLY, DEBUGGING
10 .debug_abbrev 0000210d 0000000000000000 0000000000000000 000247b8 2**0
CONTENTS, READONLY, DEBUGGING
11 .debug_aranges 00000560 0000000000000000 0000000000000000 000268c5 2**0
CONTENTS, READONLY, DEBUGGING
12 .debug_line 000030e7 0000000000000000 0000000000000000 00026e25 2**0
CONTENTS, READONLY, DEBUGGING
13 .debug_str 000026a5 0000000000000000 0000000000000000 00029f0c 2**0
CONTENTS, READONLY, DEBUGGING
14 .debug_ranges 000001b0 0000000000000000 0000000000000000 0002c5b1 2**0
CONTENTS, READONLY, DEBUGGING
because linker has moved my ap_stack to be together with stack, which is definitely what I don't want. Any reason why and how can I stop this behavior?
I'm compiling a c file foo.c:
#include <stdlib.h>
extern void *memcpy_optimized(void* __restrict, void* __restrict, size_t);
void foo() {
[blah blah blah]
memcpy_optimized((void *)a, (void *)b, 123);
}
then I have the assembly file memcpy_optimized.S:
.text
.fpu neon
.global memcpy_optimized
.type memcpy_optimized, %function
.align 4
memcpy_optimized:
.fnstart
mov ip, r0
cmp r2, #16
blt 4f # Have less than 16 bytes to copy
# First ensure 16 byte alignment for the destination buffer
tst r0, #0xF
beq 2f
tst r0, #1
ldrneb r3, [r1], #1
[blah blah blah]
.fnend
Both files compile fine with: gcc $< -o $# -c
but when I link the application with both resulting objects, I get the following error:
foo.c:(.text+0x380): undefined reference to `memcpy_optimized(void*, void *, unsigned int)'
Any idea what I'm doing wrong?
readelf -a obj/memcpy_optimized.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 436 (bytes into file)
Flags: 0x5000000, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 11
Section header string table index: 8
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000040 0000f0 00 AX 0 0 16
[ 2] .data PROGBITS 00000000 000130 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00000000 000130 000000 00 WA 0 0 1
[ 4] .ARM.extab PROGBITS 00000000 000130 000000 00 A 0 0 1
[ 5] .ARM.exidx ARM_EXIDX 00000000 000130 000008 00 AL 1 0 4
[ 6] .rel.ARM.exidx REL 00000000 00044c 000010 08 9 5 4
[ 7] .ARM.attributes ARM_ATTRIBUTES 00000000 000138 000023 00 0 0 1
[ 8] .shstrtab STRTAB 00000000 00015b 000056 00 0 0 1
[ 9] .symtab SYMTAB 00000000 00036c 0000b0 10 10 9 4
[10] .strtab STRTAB 00000000 00041c 00002f 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
Relocation section '.rel.ARM.exidx' at offset 0x44c contains 2 entries:
Offset Info Type Sym.Value Sym. Name
00000000 0000012a R_ARM_PREL31 00000000 .text
00000000 00000a00 R_ARM_NONE 00000000 __aeabi_unwind_cpp_pr0
Unwind table index '.ARM.exidx' at offset 0x130 contains 1 entries:
0x0 <memcpy_optimized>: 0x80b0b0b0
Compact model 0
0xb0 finish
0xb0 finish
0xb0 finish
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 NOTYPE LOCAL DEFAULT 1 $a
5: 00000000 0 SECTION LOCAL DEFAULT 4
6: 00000000 0 SECTION LOCAL DEFAULT 5
7: 00000000 0 NOTYPE LOCAL DEFAULT 5 $d
8: 00000000 0 SECTION LOCAL DEFAULT 7
9: 00000000 0 FUNC GLOBAL DEFAULT 1 memcpy_optimized
10: 00000000 0 NOTYPE GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr0
No version information found in this file.
Attribute Section: aeabi
File Attributes
Tag_CPU_name: "7-A"
Tag_CPU_arch: v7
Tag_CPU_arch_profile: Application
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-2
Tag_FP_arch: VFPv3
Tag_Advanced_SIMD_arch: NEONv1
Tag_DIV_use: Not allowed
It seems to me that you compiled your foo.c as C++, hence the linking error. What made me say that is that the linker reported the full prototype of the missing function. C functions do not have their full prototype as their symbol (just the name of function), however the C++ mangled names represent the full prototype of the function.
In many Unix and GCC C implementations, names in C are decorated with an initial underscore in object code. So, to call memcpy_optimized in C, you must use the name _memcpy_optimized in assembly.