This question already has answers here:
Output of 'make' is a shared object and not an executable
(2 answers)
Closed 6 years ago.
I have an application on my Ubuntu system, built with CMake, using add_executable predicate. It runs fine by itself, however, readelf shows it as DYN (Shared object file) which is usually applied to shared libraries:
root#3cced4f9860d build# readelf -h ./unittest/unittests
ELF Header:
Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - GNU
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x3e3660
Start of program headers: 64 (bytes into file)
Start of section headers: 19112592 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 28
Does anyone know why this may happen?
On modern distros executables are compiled to position-independent code by default (see e.g. this question) which causes tools (file, etc.) to think that they are shared libs. I suggest you file a bug against respective tools so that they produce more user-friendly output.
Related
Background
I've encountered a problem that violates my conceptual model of position independent code and thread local storage. The problem that prompted this can be found in this StackOverflow post; I have a binary, which in turn dlopen's a shared object. Opening the shared object triggers an error stating dlopen: cannot load any more object with static TLS.
My understanding of this is that the initial-exec model is what is referred to as "static TLS" and that this is the often default when not creating position independent code. When one creates position independent code, the default is usually something else such as the global-dynamic model that GCC uses. I believed that the reason for this was because initial-exec cannot work in a shared object. An answer to Another StackOverflow post supported this belief, stating:
Linking non-fPIC code into a shared library is impossible on x86_64, but is allowed on ix86 (and leads to many subtle problems, like this one).
Given I am on an x86_64 machine, this has lead to some confusion. I then came across another StackOverflow question, where the answer appears to create a shared object using the static TLS model.
Upon seeing this, I decided to return to my problematic binary and recursively scan dependencies for the use of the static TLS model by looking at the output of readelf -d as per the answer to this question. To my surprise, I find a few libraries. To my dismay, they are not libraries built by the application.
Here is the output of readelf -d for one of them:
/lib64/libpthread.so.0
Dynamic section at offset 0x17d90 contains 29 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]
0x000000000000000e (SONAME) Library soname: [libpthread.so.0]
0x000000000000000c (INIT) 0x38c46052d0
0x000000000000000d (FINI) 0x38c4611120
0x0000000000000004 (HASH) 0x38c4615e90
0x000000006ffffef5 (GNU_HASH) 0x38c4600280
0x0000000000000005 (STRTAB) 0x38c4602dd8
0x0000000000000006 (SYMTAB) 0x38c4600f00
0x000000000000000a (STRSZ) 4918 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x38c4817fe8
0x0000000000000002 (PLTRELSZ) 1680 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x38c4604c38
0x0000000000000007 (RELA) 0x38c4604578
0x0000000000000008 (RELASZ) 1728 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffc (VERDEF) 0x38c46043a0
0x000000006ffffffd (VERDEFNUM) 10
0x000000000000001e (FLAGS) STATIC_TLS
0x000000006ffffffb (FLAGS_1) Flags: NODELETE INITFIRST
0x000000006ffffffe (VERNEED) 0x38c46044f8
0x000000006fffffff (VERNEEDNUM) 2
0x000000006ffffff0 (VERSYM) 0x38c460410e
0x000000006ffffff9 (RELACOUNT) 60
0x000000006ffffdf8 (CHECKSUM) 0x86f709c8
0x000000006ffffdf5 (GNU_PRELINKED) 2018-05-23T11:25:00
0x0000000000000000 (NULL) 0x0
Here we can see STATIC_TLS, which leads me to believe the initial-exec model has been used.
The output of readelf -l:
Elf file type is DYN (Shared object file)
Entry point 0x38c4605de0
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x00000038c4600040 0x00000038c4600040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000011830 0x00000038c4611830 0x00000038c4611830
0x000000000000001c 0x000000000000001c R 10
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x00000038c4600000 0x00000038c4600000
0x0000000000016df0 0x0000000000016df0 R E 200000
LOAD 0x0000000000017b90 0x00000038c4817b90 0x00000038c4817b90
0x00000000000006e0 0x0000000000004860 RW 200000
DYNAMIC 0x0000000000017d90 0x00000038c4817d90 0x00000038c4817d90
0x00000000000001f0 0x00000000000001f0 RW 8
NOTE 0x0000000000000238 0x00000038c4600238 0x00000038c4600238
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x000000000001184c 0x00000038c461184c 0x00000038c461184c
0x0000000000000a5c 0x0000000000000a5c R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
GNU_RELRO 0x0000000000017b90 0x00000038c4817b90 0x00000038c4817b90
0x0000000000000470 0x0000000000000470 R 1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_d .gnu.version_r .rela.dyn .rela.plt .init .plt .text __libc_freeres_fn .fini .rodata .interp .eh_frame_hdr .eh_frame .gcc_except_table .hash
03 .ctors .dtors .jcr .data.rel.ro .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.gnu.build-id .note.ABI-tag
06 .eh_frame_hdr
07
08 .ctors .dtors .jcr .data.rel.ro .dynamic .got
I was surprised by the lack of a TLS section here, but even so we have clear indications that a shared object is using the static initial-exec TLS model.
Finally, I've seen people with similar problems reordering dependencies to get rid of the earlier dlopen error. I'm not why that makes a difference.
Question(s)
How does a initial-exec function inside relocatable code, especially shared objects on x86_64?
Why does reordering dependencies sometimes resolve the dlopen issue; surely the number of slots used remains the same?
Any other suggestions for the original dlopen issue are also welcomed.
Update 1
Whilst digging around the problem some more, I came across another source stating static TLS models cannot be use in shared libraries:
DF_STATIC_TLS
If set in a shared object or executable, this flag instructs the dynamic linker to reject attempts to load this file dynamically. It indicates that the shared object or executable contains code using a static thread-local storage scheme. Implementations need not support any form of thread-local storage.
An external USB 3.0 HDD Seagate Expantion Drive 1TB is connected to my Raspberry Pi 4B on the Raspbian Buster.
The hard drive rarely works, so the first thing I would like it to shut down during idle time (rotation stopped).
I must say right away that I tried the "hdparm" utility, but it absolutely does not work for me. On my old Raspberry Pi 3B +, it did its job perfectly, but it doesn’t work at all on the new one.
I tried doing
sudo hdparm -S 10 / dev / sda1
and
sudo hdparm -Y / dev / sda1
But all he gives out is
/dev/sda:
issuing sleep command
SG_IO: bad / missing sense data, sb []: 70 00 05 00 00 00 00 0a 00 00 00 00 24 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
At the same time, the disk continues to rotate and the LED on the case is on, no matter how much I wait
I also tried to register the following settings in hdparm.conf:
/dev/sda1 {
spindown_time = 20
}
But this also did not give any effect, the disk continues to rotate.
Also, knowing that udisks2 is installed in the raspbian buster, I tried to create a configuration file Seagate_Expansion_NA4B2GTR-0: 0.conf (this is exactly what the command "udevadm info / dev / sda" gave me) in the directory /etc/udisks2/ with the contents
[ATA]
StandbyTimeout = 20
But it didn't work either.
The fact that the disk does not stop spinning is my first problem. The second problem is that when you turn off or restart Raspberry, the disk does not park its heads and its power is interrupted abruptly, which causes a very unpleasant rattle. I found similar queries on the Internet, this is a very common problem.
I would like that during the procedure of shutting down the OS, the disk should be correctly unmounted and its power turned off before power is lost on the USB 3.0 port.
Fortunately, I was able to write a similar script and it works great:
hddshutdown.sh
sudo umount -f /dev/sda1
sudo udisksclt power-off -b /dev/sda1
sleep 5
If I run this script just while the OS is running, it does exactly what I need: The disk is unmounted, the disk rotation stops and the LED on the case goes out. However, I cannot get this script to work the same way during the OS shutdown procedure.
I wrote this unit for systemd:
hddshutdown.service in /usr/lib/systemd/system/
[Unit]
Description=[=======USB-HDD-spindown============]
DefaultDependencies=no
After=umount.target
Before=shutdown.target poweroff.target reboot.target halt.target
[Service]
ExecStart=/bin/sh /home/pi/hddshutdown.sh
Type=oneshot
RemainAfterExit=yes
[Install]
WantedBy=reboot.target
I did "sudo systemctl enable hddshutdown", tried several different configuration options, played with different Before, After, and WantedBy values, but none of the options worked, just one, the drive is successfully unmounted, but the power does not turn off, the drive continues to spin and LED is on until the moment the Pi is turned off. Moreover, I know for sure that the sh-script starts exactly, the "sleep" delay, which I set at the end of the script, really works.
I do not know Linux very well and this was my first experience writing units for systemd. I found information that udisksctl needs DBus to work, but it doesn’t exist during shutdown, and that’s why the drive’s power cannot turn off. I could not find a way to execute this unit as early as possible during the shutdown procedure when DBus is still available. (I don’t even know what it is, maybe I said stupidity)
Please help me solve 2 of these problems, thanks in advance.
I myself found the answer to my question. Because I use the Seagate Expansion drive, I used the Seagate Dashboard program from the official site to "reprogram" my hard drive. I was able to turn off the external LED-indicator and set the rotation shutdown time to 10 minutes and now on any system the hard disk is turned off after 10 minutes. Using programs like hdparm or udisks is no longer required!
What worked for me to make my HDD spin-down automatically when idle was this new implementation of hd-idle.
My particular setup is: Raspberry Pi 4B + Suptronics X835 + WD Blue WD20EZRZ.
Non of the other usual tools worked for me (hdparm, original hd-idle).
I'm trying to compile and debug an embedded rust application for stm32f0 using an ARM system as host.
The application already compiles and works under an Intel installation.
I am running on a Pinebook Pro, powered by a Quad Cortex-A53, 64-bit CPU. The OS is a 64-bit version of Debian:
$ uname -a
Linux pinebook 4.4.196 #1 SMP Tue Oct 15 16:54:21 EDT 2019 aarch64 GNU/Linux
I installed rust and cargo with rustup for AArch64 (channel stable):
$ rustc --version
rustc 1.39.0 (4560ea788 2019-11-04)
$ cargo --version
cargo 1.39.0 (1c6ec66d5 2019-09-30)
As per this issue I found out that rust-lld is not distributed in binary form for ARM systems, so I had to compile it from sources:
$ ld.lld --version
LLD 10.0.0 (https://github.com/llvm/llvm-project.git 1c247dd028b368875bc36cd2a9ccc7fd90507776) (compatible with GNU linkers)
Now the compilation process completes without issues:
export RUSTFLAGS="-C linker=ld.lld"
cargo build
However the resulting elf file seems to be linked incorrectly: trying to load it with gdb through openocd results in some kind of silent failure:
(gdb) target remote :3333
Remote debugging using :3333
0x00000000 in ?? ()
(gdb) load
Start address 0x0, load size 0
Transfer rate: 0 bits in <1 sec.
(gdb)
The load size is empty, so no new program is flashed. In contrast, when using the elf compiled in my Intel system (with openocd still running on the arm laptop) everything works as expected:
(gdb) target remote 192.168.1.153:3333
Remote debugging using 192.168.1.153:3333
0x00000000 in ?? ()
(gdb) load
Loading section .vector_table, size 0xc0 lma 0x8000000
Loading section .text, size 0x686e lma 0x80000c0
Loading section .rodata, size 0x4a0 lma 0x8006940
Start address 0x8005b58, load size 28110
Transfer rate: 19 KB/sec, 7027 bytes/write.
(gdb)
It would seems like the elf is not linked correctly. Running readelf -l highlights that on my ARM system the entry point set is 0x0, which is wrong for the stm32f0.
This is readelf on my ARM laptop:
lf file type is EXEC (Executable file)
Entry point 0x0
There are 3 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00010034 0x00010034 0x00060 0x00060 R 0x4
LOAD 0x000000 0x00010000 0x00010000 0x00094 0x00094 R 0x1000
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0
Section to Segment mapping:
Segment Sections...
00
01
02
While this is from the elf that works, compiled under my Intel system:
Elf file type is EXEC (Executable file)
Entry point 0x8005b59
There are 3 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x08000000 0x08000000 0x06de0 0x06de0 R E 0x1000
LOAD 0x007de0 0x20000000 0x08006de0 0x00000 0x00028 RW 0x1000
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0
Section to Segment mapping:
Segment Sections...
00 .vector_table .text .rodata
01 .data .bss
02
I'm not sure if this has something to do with the target architecture being the same as the host (thus using the linux userland linking) or simple because arm systems are less supported.
Can anyone point me in the right direction?
I was correct in assuming there was a problem with the linker, and there are a couple of solutions.
Since two years ago Rust uses LLD as the default linker for the ARM architecture (https://rust-embedded.github.io/blog/2018-08-2x-psa-cortex-m-breakage/). Unfortunately rust-lld itself is not distributed in binary form for the ARM platforms (ironic, isn't it?), so I had to compile it from source and specify it via command line.
Exporting the RUSTFLAGS variable works but overwrites its default value defined in .cargo/config, which would include also the directive for the linker script (-C link-arg=-Tlink.x). In short I was convinced of using the correct linker script because it was listed in .cargo/config, but the RUSTFLAGS env variable was removing it.
The solution is to either
include the linker script explicitly when exporting RUSTFLAGS:
export RUSTFLAGS="-C linker=ldd -C link-arg=-Tlink.x"
specify "-C", "linker=lld" as a rust flag in the .cargo/config file with the other options
Enable the old linker (arm-none-eabi-ld) which is more easily retrievable by uncommenting the following line in .cargo/config: "-C", "linker=arm-none-eabi-gcc"
You have to create raw binary image by using a linker srcipt dedicated to that board.
https://github.com/szczys/stm32f0-discovery-basic-template/tree/master/Device/ldscripts
You may have heard of StoneKnifeForth, a project by kragen: https://github.com/kragen/stoneknifeforth. It's a Python program that acts as a small Forth interpreter and a Forth program that acts as a Forth compiler. Therefore you can build a Forth compiler binary using those two in unison.
After porting StoneKnifeForth to C++ (https://github.com/tekknolagi/stoneknifecpp), I noticed that all binaries produced by StoneKnifeForth (either variety) segfault on 64 bit Linux. That is, if you clone stoneknifecpp and run:
make
./l01compiler # produced by the Forth program
You'll get the following:
willow% ./l01compiler
[1] 31614 segmentation fault ./l01compiler
This isn't a very interesting error message, obviously, so I thought I would strace it:
willow% strace ./l01compiler
execve("./l01compiler", ["./l01compiler"], [/* 110 vars */]) = -1 EPERM (Operation not permitted)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
+++ killed by SIGSEGV +++
[1] 31615 segmentation fault (core dumped) strace ./l01compiler
And got... somewhat more information. It looks like the ELF header is wrong somehow, except for the following two interesting tidbits:
It runs fine under 32 bit qemu
It runs fine if I sudo ./l01compiler
I'm a bit of a loss as to why this is, even after internet searching for possible differences between ELF header formats between 32 bit and 64 bit Linux kernels, etc. If anyone has any information, I would be delighted.
I have attached the header below:
willow% readelf -h l01compiler
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: Intel 80386
Version: 0x1
Entry point address: 0x1e39
Start of program headers: 52 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 0
Section header string table index: 0
Big thanks to Tom Hebb (tchebb) for confirming my suspicions and figuring this out. As can be seen in this commit, the problem was that the origin address was simply too low. It's not related to 32 bit or 64 bit, but instead earlier kernel vs newer kernel.
The newer kernels have increased the vm.mmap_min_addr sysctl parameter, meaning that the old origin would prohibit the program from starting at all. That explains why sudo worked. As Tom explained, "Unless you invoke qemu with KVM support, qemu is an emulator not a hypervisor, so it simulates the entire address space and virtual memory subsystem in software and presumably doesn't impose any load address restrictions."
I have added a new service to my CentOS box. It should be started after the mounting the file systems.
Would appreciate your assistance,
Liora
You can add the following line in /etc/init.d/<your-service-script> file.
chkconfig: - 00 99
This denotes it will start the service number as 00 (first) and while stopping it is 99 (almost last).
You can make it as 01 and it would be better.