So out of curiosity, I tried to run this code today (compiled with gcc -m32 1.c):
int main(void)
{
// EB is the opcode for jmp rel/8
// FE is hex for -2
// So this is essentially an infinite loop
((void(*)(void))"\xEB\xFE")();
}
... and it worked! No segfaults, the program (correctly?) goes into an infinite loop. Looking at the disassembly (objdump -d a.out), you can see the call to... whatever is at address 0x8048480:
080483d6 <main>:
....
80483e7: b8 80 84 04 08 mov $0x8048480,%eax
80483ec: ff d0 call *%eax
....
objdump -s -j .rodata a.out gives:
Contents of section .rodata:
8048478 03000000 01000200 ebfe00 ...........
~~~~
So it is indeed executing the string, which is stored in the .rodata section. So I ran readelf --sections a.out and got:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000020 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481cc 0001cc 000040 10 A 6 1 4
[ 6] .dynstr STRTAB 0804820c 00020c 000045 00 A 0 0 1
[ 7] .gnu.version VERSYM 08048252 000252 000008 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0804825c 00025c 000020 00 A 6 1 4
[ 9] .rel.dyn REL 0804827c 00027c 000008 08 A 5 0 4
[10] .rel.plt REL 08048284 000284 000008 08 AI 5 23 4
[11] .init PROGBITS 0804828c 00028c 000023 00 AX 0 0 4
[12] .plt PROGBITS 080482b0 0002b0 000020 04 AX 0 0 16
[13] .plt.got PROGBITS 080482d0 0002d0 000008 00 AX 0 0 8
[14] .text PROGBITS 080482e0 0002e0 000182 00 AX 0 0 16
[15] .fini PROGBITS 08048464 000464 000014 00 AX 0 0 4
[16] .rodata PROGBITS 08048478 000478 00000b 00 A 0 0 4
[17] .eh_frame_hdr PROGBITS 08048484 000484 000034 00 A 0 0 4
[18] .eh_frame PROGBITS 080484b8 0004b8 0000e0 00 A 0 0 4
[19] .init_array INIT_ARRAY 08049f0c 000f0c 000004 04 WA 0 0 4
[20] .fini_array FINI_ARRAY 08049f10 000f10 000004 04 WA 0 0 4
[21] .dynamic DYNAMIC 08049f14 000f14 0000e8 08 WA 6 0 4
[22] .got PROGBITS 08049ffc 000ffc 000004 04 WA 0 0 4
[23] .got.plt PROGBITS 0804a000 001000 000010 04 WA 0 0 4
[24] .data PROGBITS 0804a010 001010 000008 00 WA 0 0 4
[25] .bss NOBITS 0804a018 001018 000004 00 WA 0 0 1
[26] .comment PROGBITS 00000000 001018 00001a 01 MS 0 0 1
[27] .symtab SYMTAB 00000000 001034 0003f0 10 28 45 4
[28] .strtab STRTAB 00000000 001424 0001bd 00 0 0 1
[29] .shstrtab STRTAB 00000000 0015e1 000105 00 0 0 1
So in the ELF binary, the section is marked non-executable. But in memory, the page is executable (cat /proc/xxx/maps):
08048000-08049000 r-xp 00000000 08:01 663551 /home/andrew/Desktop/a.out
08049000-0804a000 r--p 00000000 08:01 663551 /home/andrew/Desktop/a.out
0804a000-0804b000 rw-p 00001000 08:01 663551 /home/andrew/Desktop/a.out
My original guess was that the sections too closely-spaced (there are both AX and A sections in the 08048000-08049000 range), so Linux is forced to give the page the union of the ELF permission bits (AX | A == AX). However, even after increasing the size of the .rodata section (by adding many long strings), all of the pages containing the .rodata section are still executable. Why is this?
(For the record, I'm running on Linux kernel 4.11.7, GCC 7.1.1, and compiling as 64-bit still exhibits this behavior)
My original guess was that the segments too closely-spaced
You should not call sections segments (ELF has both, and they mean different things).
Sections only matter at static link time, and can be completely removed (are not needed at runtime). Only segments matter at runtime, and a typical ELF binary will have two segments with R-X and RW- permissions.
The .rodata section is usually merged with .text section and put into the executable segment. You can change that with the --rosegment flag if you use gold linker (patch which introduced this).
You can see section to segment mapping in the readelf -Wl a.out output.
Update:
Can there ever be a situation where .rodata needs to be executable, or is it for optimization, or something else?
There are no portable situations where .rodata needs to be executable. It is possible to construct a non-portable program that requires it, as you've done in your question.
Merging of .rodata and .text is an optimization: it requires two mmap calls instead of three (a program linked with --rosegment will have three separate PT_LOAD segments with R-X, R-- and R-W protections) and also fragments the virtual space less. In addition, on Linux there is a system-wide limit on total mappings, so you'll reduce the total number of programs you can run at once by 50% if you link everything with --rosegment.
Update 2:
Recent Linux distributions stopped merging .text and .rodata, and now have three or four separate LOAD segments. See this answer.
Related
I have memory leak somewhere and unfortunately the repeated topic which appears on stack overflow didn't help; I don't really understand how this happens since I identified the dubious line from gdb run,
void read_data(std::string filename, number_type & parameter, number_type & n_part, number_type & mult){
std::ifstream infile(filename);
std::string line; // ERROR LINE
size_type counter_numbers = 0;
size_type counter_lines = 0;
while (infile)
{
std::getline(infile, line); // Read in current line
.
.
this is where it shows in gdb: free(): invalid next size (normal);
at string definition. Why would this happen; Any ideas?
thanks, Damir
Running as
g++ -std=c++11 -I/users/damir/gsl/include/ -L/users/damir/gsl/lib/ -lgsl -lgslcblas -g -o MultB analysis_mult_b.cpp
PS (valgrind output)
valgrind ./MultB arg1 arg2 arg3 arg4
==39918== Command: ./MultB arg1 arg2 arg3 arg4
==39918==
==39918== Invalid write of size 8
==39918== at 0x405B55: ??? (in /users/damir/Analysis/MultB)
==39918== by 0x404531: ??? (in /users/damir/Analysis/MultB)
==39918== by 0x5582B44: (below main) (libc-start.c:287)
==39918== Address 0x591e530 is 0 bytes after a block of size 400 alloc'd
==39918== at 0x4C28C20: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==39918== by 0x512B654: ??? (in /cvmfs/it/compiler/gcc/9.1.0/lib64/libstdc++.so.6.0.26)
==39918== by 0x404531: ??? (in /users/damir/Analysis/MultB)
==39918== by 0x5582B44: (below main) (libc-start.c:287)
==39918==
--39918-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--39918-- si_code=80; Faulting address: 0x0; sp: 0x802b99de0
valgrind: the 'impossible' happened:
Killed by fatal signal
host stacktrace:
==39918== at 0x380B1870: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==39918== by 0x38072784: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==39918== by 0x38072956: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==39918== by 0x380F6D27: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==39918== by 0x38105B60: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
sched status:
running_tid=1
Thread 1: status = VgTs_Runnable
==39918== at 0x4C28C20: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==39918== by 0x512B654: ??? (in /cvmfs/it/compiler/gcc/9.1.0/lib64/libstdc++.so.6.0.26)
==39918== by 0x40455D: ??? (in /users/damir/Analysis/MultB)
==39918== by 0x5582B44: (below main) (libc-start.c:287)
Output from readlef -WS ./MultB:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00000000004002a8 0002a8 00001c 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 00000000004002c4 0002c4 000020 00 A 0 0 4
[ 3] .hash HASH 00000000004002e8 0002e8 000334 04 A 5 0 8
[ 4] .gnu.hash GNU_HASH 0000000000400620 000620 00005c 00 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000400680 000680 0009f0 18 A 6 1 8
[ 6] .dynstr STRTAB 0000000000401070 001070 000fe1 00 A 0 0 1
[ 7] .gnu.version VERSYM 0000000000402052 002052 0000d4 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000402128 002128 0000c0 00 A 6 4 8
[ 9] .rela.dyn RELA 00000000004021e8 0021e8 000048 18 A 5 0 8
[10] .rela.plt RELA 0000000000402230 002230 000918 18 AI 5 24 8
[11] .init PROGBITS 0000000000403000 003000 00001a 00 AX 0 0 4
[12] .plt PROGBITS 0000000000403020 003020 000620 10 AX 0 0 16
[13] .plt.got PROGBITS 0000000000403640 003640 000008 08 AX 0 0 8
[14] .text PROGBITS 0000000000403650 003650 00a342 00 AX 0 0 16
[15] .fini PROGBITS 000000000040d994 00d994 000009 00 AX 0 0 4
[16] .rodata PROGBITS 000000000040e000 00e000 000208 00 A 0 0 16
[17] .eh_frame_hdr PROGBITS 000000000040e208 00e208 0010cc 00 A 0 0 4
[18] .eh_frame PROGBITS 000000000040f2d8 00f2d8 004568 00 A 0 0 8
[19] .gcc_except_table PROGBITS 0000000000413840 013840 00049c 00 A 0 0 4
[20] .init_array INIT_ARRAY 0000000000414db0 013db0 000010 08 WA 0 0 8
[21] .fini_array FINI_ARRAY 0000000000414dc0 013dc0 000008 08 WA 0 0 8
[22] .dynamic DYNAMIC 0000000000414dc8 013dc8 000230 10 WA 6 0 8
[23] .got PROGBITS 0000000000414ff8 013ff8 000008 08 WA 0 0 8
[24] .got.plt PROGBITS 0000000000415000 014000 000320 08 WA 0 0 8
[25] .data PROGBITS 0000000000415320 014320 000010 00 WA 0 0 8
[26] .bss NOBITS 0000000000415340 014330 000138 00 WA 0 0 32
[27] .comment PROGBITS 0000000000000000 014330 00002d 01 MS 0 0 1
[28] .debug_aranges PROGBITS 0000000000000000 01435d 002060 00 0 0 1
[29] .debug_info PROGBITS 0000000000000000 0163bd 024611 00 0 0 1
[30] .debug_abbrev PROGBITS 0000000000000000 03a9ce 000e97 00 0 0 1
[31] .debug_line PROGBITS 0000000000000000 03b865 005f1d 00 0 0 1
[32] .debug_str PROGBITS 0000000000000000 041782 025677 01 MS 0 0 1
[33] .debug_ranges PROGBITS 0000000000000000 066df9 002260 00 0 0 1
[34] .symtab SYMTAB 0000000000000000 069060 004e60 18 35 57 8
[35] .strtab STRTAB 0000000000000000 06dec0 00a877 00 0 0 1
[36] .shstrtab STRTAB 0000000000000000 078737 000154 00 0 0 1
I have memory leak somewhere
You may have, but you have provided no evidence of that.
The problem is subject line: free(): invalid next size (normal) is not about a memory leak, but rather about heap corruption.
I don't really understand how this happens
Heap corruption bugs often show up as a crash quite far from where they actually happen. This makes finding them without specialized tools hard.
Fortunately, there are specialized tools. Run your program under Valgrind, or with Address Sanitizer.
Update:
Invalid write of size 8
==39918== at 0x405B55: ??? (in /users/damir/Analysis/MultB)
==39918== by 0x404531: ??? (in /users/damir/Analysis/MultB)
==39918== by 0x5582B44: (below main) (libc-start.c:287)
==39918== Address 0x591e530 is 0 bytes after a block of size 400 alloc'd
That's the heap corruption right there: you are writing 8 bytes past the end of a heap block.
Unfortunately you didn't build MultB with debug info, so Valgrind can't tell you where in the source this is happening.
Rebuild your application with -g flag, run it under Valgrind again, and fix the bug Valgrind told you about.
I am working with a imx6 dual light digi board. I want to add Ad7879 touch support. I 've been followed the next steps:
-First I changed the kernel config file adding support fo touchscreen and ad7879. In kernel config file I 've made the following changes:
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_AD7879=y
CONFIG_TOUCHSCREEN_AD7879_I2C=y
At the first I configured ad7879 as module doing:
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_AD7879=m
CONFIG_TOUCHSCREEN_AD7879_I2C=m
After that I made the device initialization in the device tree.
In imx6qdl-ccimx6sbc.dtsi file I put the next:
&i2c3 {
ad7879#2c
{
compatible = "adi,ad7879-1";
reg = <0x2c>;
interrupt-parent = <&gpio6>;
interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
touchscreen-max-pressure = <4096>;
adi,resistance-plate-x = <120>;
adi,first-conversion-delay = /bits/ 8 <3>;
adi,acquisition-time = /bits/ 8 <1>;
adi,median-filter-size = /bits/ 8 <2>;
adi,averaging = /bits/ 8 <1>;
adi,conversion-interval = /bits/ 8 <255>;
};
The ad7879 interrupt controller is conected to the imx6 in EXP_I2C_IRQ_N pin that is the GPIO_6_15, for that reason I put interrupt-parent = <&gpio6> and interrupts = <15 IRQ_TYPE_EDGE_FALLING>;.
In imx6qdl-ccimx6sbc.dts file I put:
&i2c3 {
...
ad7879#2c {
status ="okay";
};
...
};
Then I followed with compile the linux image and device tree.
In the imx6 with the linux image that I configures the ad7879 as module I loaded the ad7879 modules doing this:
root:~> modprobe ad7879
root:~> modprobe ad7879-i2c
but there is not log messages abaout the ad7879 and there is no ad7879 node asociated.
If I check the device node to chek the device node:
root#ccimx6sbc: ls -la /dev/input/
drwxr-xr-x 4 root root 180 Jan 1 2000 .
drwxr-xr-x 14 root root 3480 May 16 14:49 ..
drwxr-xr-x 2 root root 80 Jan 1 2000 by-id
drwxr-xr-x 2 root root 120 Jan 1 2000 by-path
crw-rw---- 1 root input 13, 64 Jan 1 2000 event0
crw-rw---- 1 root input 13, 65 Jan 1 2000 event1
crw-rw---- 1 root input 13, 66 Jan 1 2000 event2
crw-rw---- 1 root input 13, 63 Jan 1 2000 mice
crw-rw---- 1 root input 13, 32 Jan 1 2000 mouse0
root#ccimx6sbc:# cat /sys/class/input/input0/name
da9063-onkey
root#ccimx6sbc:# cat /sys/class/input/input1/name
Genius 4D Scroll Mouse
root#ccimx6sbc:# cat /sys/class/input/input2/name
sgtl5000-audio Headphone Jack
You can see that there is no node asociated.
root#ccimx6sbc:# cat /proc/interrupts
CPU0 CPU1
29: 140884 13795 GIC 29 twd
34: 406 0 GIC 34 sdma
35: 0 0 GIC 35 VPU_JPG_IRQ
37: 1 0 GIC 37 2400000.ipu
38: 12 0 GIC 38 2400000.ipu
42: 28 0 GIC 42
44: 0 0 GIC 44 VPU_CODEC_IRQ
50: 0 0 GIC 50 vdoa
51: 0 0 GIC 51 rtc alarm
54: 52 0 GIC 54 mmc3
55: 52 0 GIC 55 mmc1
57: 3580 0 GIC 57 mmc0
61: 353 0 GIC 61 21f0000.serial
63: 0 0 GIC 63 2008000.ecspi
69: 472 0 GIC 69 21a4000.i2c
70: 1367 0 GIC 70 21a8000.i2c
72: 109 0 GIC 72 2184200.usb
75: 0 0 GIC 75 2184000.usb
79: 0 0 GIC 79 202c000.ssi
81: 0 0 GIC 81 imx_thermal
87: 167 0 GIC 87 i.MX Timer Tick
112: 0 0 GIC 112 20bc000.wdog
134: 0 0 GIC 134 mipi_dsi
137: 466 0 GIC 137 2101000.jr0
138: 0 0 GIC 138 2102000.jr1
139: 0 0 GIC 139 mmdc_1
144: 0 0 GIC 144 mmdc_1
147: 0 0 GIC 147 20e0000.hdmi_video
150: 62234 0 GIC 150 2188000.ethernet
151: 0 0 GIC 151 2188000.ethernet
192: 0 0 gpio-mxc 0 headphone detect
364: 1 0 gpio-mxc 12 da9063-irq
413: 0 1 da9063-irq 3 HWMON
414: 0 0 da9063-irq 0 ONKEY
415: 0 0 da9063-irq 1 ALARM
IPI0: 0 0 CPU wakeup interrupts
IPI1: 0 58 Timer broadcast interrupts
IPI2: 1405 2387 Rescheduling interrupts
IPI3: 0 0 Function call interrupts
IPI4: 19 33 Single function call interrupts
IPI5: 0 0 CPU stop interrupts
IPI6: 426 476 IRQ work interrupts
IPI7: 0 0 completion interrupts
Err: 0
You can se that there is not interrupts asociated to ad7879.
There is no difference when I build the linux kernel with this configuration:
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_AD7879=y
CONFIG_TOUCHSCREEN_AD7879_I2C=y
I did run dmesg and there is no log entries associated with ad7879.
In the imx6 linux I did the following commands:
>root#ccimx6sbc:i2cdetect 2
with this response:
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-2.
I will probe address range 0x03-0x77.
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- UU -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- 2c -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
If you can see the identifier of the device is detected (0x2c).
Then I made:
>root#ccimx6sbc: i2cdump -r 0-0x40 2 0x2c
With this response:
No size specified (using byte-data access)
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-2, address 0x2c, mode byte
Probe range limited to 0x00-0x40.
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 00 00 40 00 00 00 00 00 00 00 00 00 00 00 03 00 ..#...........?.
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
40: 00
You can se in 0x02 and 0x0e are two of the default values for the registers of ad7879 and they are correct. So I concluded that the controller is well connected.
I don't if I missing something.
I'm learning about elf binaries. I want to manually verify that the code written in the program is in an executable region of memory (same for code for shared library that will be linked).
I have a simple program:
int main() { return 0; }
When I do:
readelf -a myprog
I get the following:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000020 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481cc 0001cc 000040 10 A 6 1 4
[ 6] .dynstr STRTAB 0804820c 00020c 000045 00 A 0 0 1
[ 7] .gnu.version VERSYM 08048252 000252 000008 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0804825c 00025c 000020 00 A 6 1 4
[ 9] .rel.dyn REL 0804827c 00027c 000008 08 A 5 0 4
[10] .rel.plt REL 08048284 000284 000010 08 A 5 12 4
[11] .init PROGBITS 08048294 000294 00002e 00 AX 0 0 4
[12] .plt PROGBITS 080482d0 0002d0 000030 04 AX 0 0 16
[13] .text PROGBITS 08048300 000300 00016c 00 AX 0 0 16
[14] .fini PROGBITS 0804846c 00046c 00001a 00 AX 0 0 4
[15] .rodata PROGBITS 08048488 000488 000008 00 A 0 0 4
[16] .eh_frame_hdr PROGBITS 08048490 000490 000034 00 A 0 0 4
[17] .eh_frame PROGBITS 080484c4 0004c4 0000c4 00 A 0 0 4
[18] .ctors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4
[19] .dtors PROGBITS 08049f1c 000f1c 000008 00 WA 0 0 4
[20] .jcr PROGBITS 08049f24 000f24 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 08049f28 000f28 0000c8 08 WA 6 0 4
[22] .got PROGBITS 08049ff0 000ff0 000004 04 WA 0 0 4
[23] .got.plt PROGBITS 08049ff4 000ff4 000014 04 WA 0 0 4
[24] .data PROGBITS 0804a008 001008 000008 00 WA 0 0 4
[25] .bss NOBITS 0804a010 001010 000008 00 WA 0 0 4
[26] .comment PROGBITS 00000000 001010 00002a 01 MS 0 0 1
[27] .shstrtab STRTAB 00000000 00103a 0000fc 00 0 0 1
[28] .symtab SYMTAB 00000000 0015e8 000400 10 29 45 4
[29] .strtab STRTAB 00000000 0019e8 0001ea 00 0 0 1
To check whether the code of the program is executable, I can see the .text section with the flags AX. Is the X here for making the code inside my main() function is executable ?
Which section will the shared library (e.g. glibc) be loaded into when the program is dynamically linked at run time ? I found explanation online which discussed use of GOT,PLT in context of dynamic linking. The only sections with the mark X are init, plt and fini (in addition to text). Are shared libraries linked into one of these sections to make sure their code is executable when program starts execution ?
(It would be great if some reference(s) could be pointed at when answering the above)
Is the X here for making the code inside my main() function is executable ?
Correct. Although more than just your main() function is involved; there is some other code which is linked into your executable that is also contained in this section.
Which section will the shared library (e.g. glibc) be loaded into when the program is dynamically linked at run time ?
None of them. The shared library is a separate ELF object, and has its own sections, some of which are executable; it is essentially loaded alongside your executable, not into it. That is, the resulting image in memory will contain both your executable's .text section and a number of other .text (and other types of) sections from all the shared libraries it has loaded.
For example, here is the content of /proc/self/maps from a running /bin/cat process on my Linux system. The format of this output is different from what readelf is showing you, but some similarities should become apparent:
00400000-0040b000 r-xp 00000000 08:00 32968 /bin/cat
0060a000-0060b000 r--p 0000a000 08:00 32968 /bin/cat
0060b000-0060c000 rw-p 0000b000 08:00 32968 /bin/cat
0242a000-0244b000 rw-p 00000000 00:00 0 [heap]
7fdf299a2000-7fdf29c6b000 r--p 00000000 08:00 949 /usr/lib/locale/locale-archive
7fdf29c6b000-7fdf29e26000 r-xp 00000000 08:00 18508 /lib/x86_64-linux-gnu/libc-2.19.so
7fdf29e26000-7fdf2a025000 ---p 001bb000 08:00 18508 /lib/x86_64-linux-gnu/libc-2.19.so
7fdf2a025000-7fdf2a029000 r--p 001ba000 08:00 18508 /lib/x86_64-linux-gnu/libc-2.19.so
7fdf2a029000-7fdf2a02b000 rw-p 001be000 08:00 18508 /lib/x86_64-linux-gnu/libc-2.19.so
7fdf2a02b000-7fdf2a030000 rw-p 00000000 00:00 0
7fdf2a030000-7fdf2a053000 r-xp 00000000 08:00 18255 /lib/x86_64-linux-gnu/ld-2.19.so
7fdf2a246000-7fdf2a249000 rw-p 00000000 00:00 0
7fdf2a250000-7fdf2a252000 rw-p 00000000 00:00 0
7fdf2a252000-7fdf2a253000 r--p 00022000 08:00 18255 /lib/x86_64-linux-gnu/ld-2.19.so
7fdf2a253000-7fdf2a254000 rw-p 00023000 08:00 18255 /lib/x86_64-linux-gnu/ld-2.19.so
7fdf2a254000-7fdf2a255000 rw-p 00000000 00:00 0
7ffd516aa000-7ffd516cb000 rw-p 00000000 00:00 0 [stack]
7ffd517f9000-7ffd517fb000 r--p 00000000 00:00 0 [vvar]
7ffd517fb000-7ffd517fd000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
In particular, you can see three sections were loaded from /bin/cat at the top: the first one is executable (r-xp), the second one is read-only (r--p), and the third is read-write (rw-p). Additionally, there are a number of executable and non-executable segments mapped from libc-2.19.so below that, as well as from ld-2.19.so (the dynamic linker).
(There are also some somewhat mysterious segments appearing in this dump, including [vdso] and [vsyscall]. These are mapped into the process by the kernel, and are difficult to explain; I won't get into them here.)
I wrote a "hello world" program with PIE/PIC enabled. I observed the program headers have 2 LOAD entries:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
... ...
LOAD 0x000000 0x00000000 0x00000000 0x00870 0x00870 R E 0x1000
LOAD 0x000eb0 0x00001eb0 0x00001eb0 0x0015c 0x00164 RW 0x1000
So in my understanding, the ELF binary will be loaded into 2 pages. The 1st page contains the binary from offset 0 to file size 0x870, and it is Read & Execute. Since they are 0x1000 aligned, the 2nd entry will be loaded in the 2nd page, which contains the binary(from offset 0xeb0 to 0xeb0+0x15c). This page has Read & Write privilege.
While I "pmap" the running process (or cat /proc/pid/maps), it show there are 3 pages for the running program:
b7554000 4K rw--- [ anon ]
b7555000 1700K r-x-- libc-2.19.so
b76fe000 4K ----- libc-2.19.so
b76ff000 8K r---- libc-2.19.so
b7701000 4K rw--- libc-2.19.so
b7702000 12K rw--- [ anon ]
b771b000 16K rw--- [ anon ]
b771f000 4K r-x-- [ anon ]
b7720000 128K r-x-- ld-2.19.so
b7740000 4K r---- ld-2.19.so
b7741000 4K rw--- ld-2.19.so
b7742000 4K r-x-- main
b7743000 4K r---- main
b7744000 4K rw--- main
bfe68000 132K rw--- [ stack ]
total 2032K
So how the ELF binary is loaded, and how the program header indicates a LOAD directive?
Part of the sections headers like:
[13] .text PROGBITS 00000480 000480 0002c2 00 AX 0 0 16
[14] .fini PROGBITS 00000744 000744 000014 00 AX 0 0 4
[15] .rodata PROGBITS 00000758 000758 000060 00 A 0 0 4
[16] .eh_frame PROGBITS 000007b8 0007b8 000094 00 A 0 0 4
[17] .eh_frame_hdr PROGBITS 0000084c 00084c 000024 00 A 0 0 4
[18] .jcr PROGBITS 00001eb0 000eb0 000004 00 WA 0 0 4
[19] .fini_array FINI_ARRAY 00001eb4 000eb4 000004 00 WA 0 0 4
[20] .init_array INIT_ARRAY 00001eb8 000eb8 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 00001ebc 000ebc 000108 08 WA 5 0 4
[22] .got PROGBITS 00001fc4 000fc4 00001c 00 WA 0 0 4
[23] .got.plt PROGBITS 00001fe0 000fe0 000020 00 WA 0 0 4
[24] .data PROGBITS 00002000 001000 00000c 00 WA 0 0 4
[25] .tm_clone_table PROGBITS 0000200c 00100c 000000 00 WA 0 0 4
[26] .bss NOBITS 0000200c 00100c 000008 00 WA 0 0 4
I observed the program headers have 2 LOAD entries:
You've omitted an important program header: GNU_RELRO, which tells the loader that after mapping the LOAD segments, it should mprotect part of them as read-only.
When mprotect with different permissions is called on existing mapping, the kernel has to split that mapping into multiple mappings, which is where the extra entry is coming from.
In my test binary:
LOAD 0x000000 0x00000000 0x00000000 0x0075c 0x0075c R E 0x1000
LOAD 0x000ef4 0x00001ef4 0x00001ef4 0x0012c 0x00130 RW 0x1000
...
GNU_RELRO 0x000ef4 0x00001ef4 0x00001ef4 0x0010c 0x0010c R 0x1
The kernel actually maps the LOAD segments before the loader even starts, and the map at that point looks like this:
56555000-56556000 r-xp 00000000 fc:02 801500 /tmp/a.out
56556000-56558000 rw-p 00000000 fc:02 801500 /tmp/a.out
f7fdb000-f7fdc000 r-xp 00000000 00:00 0 [vdso]
...
After the mprotect, the map looks like this:
56555000-56556000 r-xp 00000000 fc:02 801500 /tmp/a.out
56556000-56557000 r--p 00000000 fc:02 801500 /tmp/a.out
56557000-56558000 rw-p 00001000 fc:02 801500 /tmp/a.out
...
I have a library that I got from a proprietary source and I'm trying to link against it but I'm getting the following error
libxxx.so: file not recognized: File format not recognized
collect2: ld returned 1 exit status
and indeed
$ ldd ./libxxx.so
statically linked
what does that exactly mean? Never saw a statically linked .so in my life. It might be worth noting that the last version of the same software included the same .so for which ldd shows the "normal" output and that works fine.
$ file ./libxxx.so
./libxxx.so: ELF 32-bit LSB shared object, Intel 80386, version 1
(SYSV), stripped
but nm, objdump also can't see anything and readelf returns errors reading string table. Am I safe to assume this .so is botched or there is something else I can try before going to "enterprise support" and waiting for two months for them to acknowledge my existence.
$ objdump -a libxxx.so
objdump: libxxx.so: File format not recognized
$ readelf -a libxxx.so
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: DYN (Shared object file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x4f00
Start of program headers: 52 (bytes into file)
Start of section headers: 147936 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 4
Size of section headers: 40 (bytes)
Number of section headers: 29
Section header string table index: 26
readelf: Error: Unable to read in 0xb70000 bytes of string table
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] <no-name> <unknown>: b400 08e40000 020000 000000 b0000 xo 262144 262144 2162688
[ 1] <no-name> <unknown>: 9980 13000000 030000 1a0000 30000 xo 262144 1048576 2686976
[ 2] <no-name> <unknown>: 1c98 13ad0000 000000 000000 ffff0000 xop 65536 0 3211264
[ 3] <no-name> <unknown>: 3046 02600000 020000 000000 fffe0000 xxop 131072 131072 4063232
[ 4] <no-name> <unknown>: 32a8 00400000 030000 010000 90000 xop 262144 0 5046272
[ 5] <no-name> <unknown>: 32e8 12c00000 020000 000000 90000 xop 262144 524288 5636096
[ 6] <no-name> <unknown>: 45a8 03100000 020000 090000 10000 xop 262144 524288 6225920
[ 7] <no-name> <unknown>: 48b8 00170000 000000 000000 10000 xop 262144 0 5898240
[ 8] <no-name> <unknown>: 48d0 06300000 000000 000000 10000 op 262144 262144 6619136
[ 9] <no-name> <unknown>: 4f00 59740000 000001 000000 10000 op 1048576 0 7012352
[10] <no-name> LOUSER+28740000 001a0001 000000 000000 10000 Wxop 262144 0 7405568
[11] <no-name> LOUSER+28a00000 7bb60001 000000 000000 10000 Wop 2097152 0 7929856
[12] <no-name> <unknown>: 3000 09900002 000000 000000 10000 Ap 2097152 0 8323072
[13] <no-name> <unknown>: 3990 00040002 000000 000000 60000 Aop 262144 0 8978432
[14] <no-name> <unknown>: 3994 00d80002 030000 000000 10000 Axop 262144 524288 9568256
[15] <no-name> <unknown>: 3a6c 00080002 000000 000000 10000 Axxop 262144 0 10027008
[16] <no-name> <unknown>: 3a74 00080002 000000 000000 10000 Axop 262144 0 10485760
[17] <no-name> <unknown>: 3a7c 00040002 000000 000000 10000 Axxop 262144 0 10813440
[18] <no-name> <unknown>: 3a80 020c0002 000000 000000 80000 Aop 262144 262144 11141120
[19] <no-name> <unknown>: 3c8c 001c0002 000000 000000 10000 Axxop 262144 0 11468800
[20] <no-name> NULL 01ee0002 000000 000000 10000 xxop 65536 0 12058624
[21] <no-name> NULL 00580002 000000 000000 10000 op 524288 0 13041664
[22] <no-name> NULL 00fa0002 000000 000000 10000 xop 65536 0 13828096
[23] <no-name> NULL 00200002 000000 000000 10000 xop 65536 0 14745600
[24] <no-name> NULL 01000002 000000 000000 30000 xop 65536 0 1114112
[25] <no-name> NULL 00ed0002 000000 000000 20000 xop 65536 0 65536
[26] <no-name> NULL 1cd00002 1c0000 b70000 30000 xop 262144 1048576 589824
[27] <no-name> NULL 194d0002 000000 000000 00 xop 65536 0 0
[28] <no-name> NULL 00b40000 000000 030000 30000 1 160956416 0
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x00000000 0x00000000 0x22456 0x22456 R E 0x1000
LOAD 0x023000 0x00023000 0x00023000 0x00c8c 0x00ca8 RW 0x1000
readelf: Error: no .dynamic section in the dynamic segment
DYNAMIC 0x023994 0x00023994 0x00023994 0x000d8 0x000d8 RW 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
There is no dynamic section in this file.
There are no relocations in this file.
There are no unwind sections in this file.
No version information found in this file.
Am I safe to assume this .so is botched
Yes, a .so file without a .dynamic section is almost certainly botched.
Did someone do an ASCII ftp transfer on it?