why my x64 process base address not start from 0x400000? - c

I learned from this link Why is address 0x400000 chosen as a start of text segment in x86_64 ABI? that 64-bit Linux process start address by default should be 0x400000, but on my Ubuntu, I only found my bash process starts from a very high base address (0x55971cea6000).
Any one knows why? and how does dynamic linker choose the start address for a 64-bit process?
$ uname -r
5.15.0-25-generic
$ cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04 LTS"
...
$ file /usr/bin/bash
/usr/bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=33a5554034feb2af38e8c75872058883b2988bc5, for GNU/Linux 3.2.0, stripped
$ ld -verbose | grep -i text-segment
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
$ cat maps
55971ce77000-55971cea6000 r--p 00000000 08:02 153 /usr/bin/bash
55971cea6000-55971cf85000 r-xp 0002f000 08:02 153 /usr/bin/bash
55971cf85000-55971cfbf000 r--p 0010e000 08:02 153 /usr/bin/bash
55971cfc0000-55971cfc4000 r--p 00148000 08:02 153 /usr/bin/bash
55971cfc4000-55971cfcd000 rw-p 0014c000 08:02 153 /usr/bin/bash
55971cfcd000-55971cfd8000 rw-p 00000000 00:00 0
...
$ readelf -h /usr/bin/bash
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: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x32eb0
Start of program headers: 64 (bytes into file)
Start of section headers: 1394600 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29

I learned from this link Why is address 0x400000 chosen as a start of text segment in x86_64
That address is used for executables (ELF type ET_EXEC).
I only found my bash process starts from a very high base address (0x55971cea6000). Any one knows why?
Because your bash is (newer) position-independent executable (ELF type ET_DYN). It behaves much like a shared library, and is relocated to random address at runtime.
The 0x55971cea6000 address you found will vary from one execution to another. In contrast, ET_EXEC executables can only run correctly when loaded at their "linked at" address (typically 0x400000).
how does dynamic linker choose the start address for a 64-bit process?
The dynamic linker doesn't choose the start address of the executable -- the kernel does (by the time the dynamic linker starts running, the executable has already been mmaped into memory).
The kernel looks at the .e_type in the ELF header and .p_vaddr field of the first program header and goes from there. IFF .e_type == ET_EXEC, then the kernel maps executable segments at their .p_vaddr addresses. For ET_DYN, if ASLR is in effect, the kernel performs mmaps at a random address.

Related

How can I know if an ELF file is for Cortex-A or Cortex-M?

I have a question when doing the binary analysis. For a given ELF file (hello.elf) that has already been identified for the ARM architecture, how can I quickly know if this ELF is for Cortex-A or Cortex-M? More specifically, I'm trying to identify the whole bare-metal images (or RTOS images like FreeRTOS) for the Cortex-M.
From the result of file hello.elf:
% file hello.elf
hello.elf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
We can only see that this ELF is for ARM.
And from the result of readelf -h ./hello.elf:
% readelf -h ./hello.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: 0xcb5
Start of program headers: 52 (bytes into file)
Start of section headers: 150896 (bytes into file)
Flags: 0x5000200, Version5 EABI, soft-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 5
Size of section headers: 40 (bytes)
Number of section headers: 19
Section header string table index: 17
It's also only showing this file is for the ARM architecture.
So are there any other approaches that can quickly identify the target architecture of an ELF file?
If your binary follows the Arm ELF specification there is an attribute section that contains information on the cpu architecture and (if applicable) the architecture profile. This information can be extracted by readelf. Note that the information is the compiler and linkers view of things and can sometimes be wrong.
The first example below is from a binary built for Cortex-A8 and the second example is a binary built for Cortex-M33. Both are built using the IAR toolchain.
> readelf -A cortex-a8.out
Attribute Section: aeabi
File Attributes
Tag_conformance: "2.10"
Tag_CPU_arch: v7
Tag_CPU_arch_profile: Application
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-2
Tag_PCS_config: Bare platform
Tag_ABI_align_needed: 8-byte
Tag_ABI_align_preserved: 8-byte, except leaf SP
Tag_ABI_enum_size: small
Tag_ABI_VFP_args: compatible
Tag_CPU_unaligned_access: v6
Tag_DIV_use: Not allowed
> readelf -A cortex-m33.out
Attribute Section: aeabi
File Attributes
Tag_conformance: "2.10"
Tag_CPU_arch: v8-M.mainline
Tag_CPU_arch_profile: Microcontroller
Tag_THUMB_ISA_use: Yes
Tag_FP_arch: FPv5/FP-D16 for ARMv8
Tag_PCS_config: Bare platform
Tag_ABI_align_needed: 8-byte
Tag_ABI_align_preserved: 8-byte, except leaf SP
Tag_ABI_enum_size: forced to int
Tag_ABI_HardFP_use: SP only
Tag_ABI_VFP_args: compatible
Tag_CPU_unaligned_access: v6
Tag_DIV_use: Not allowed

cross compilation for ARM: error no such file or directory/command not found

I have written simple Hello world program and compiled it with gcc-arm-linux-gnueabi compiler. It compiles well but when i try to execute it on ARM machine it complains "no such file or directory". I think gcc-arm-linux-gnueabi is for embedded Linux only due to e(mbedded)abi. Is it different from ARM Linux ABI?
Please help me to solve this problem
code is here
#include "stdio.h"
int main(void) {
printf("Hello world !\n");
return 0;
}
compiled as
arm-linux-gnueabi-gcc -Wall -o crosscomp hello.c
When i execute this crosscomp on target ARM machine error is crosscomp no such file or dir
EDIT When I was using arm-linux-gnueabi-gcc the entry point was not matching with the target machine entry point (readelf -l crosscom) but when I compiled with aarch64-linux-gnu-gcc entry point matched with target machine. But now error becomes permission denied on ./crosscomp. I tried with sudo which says crosscomp: no such command.
Note I posted same question on askubuntu https://askubuntu.com/questions/904685/cross-compilation-for-arm-error-no-such-file-or-directory but got no response.
The output of readelf is as below
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: AArch64
Version: 0x1
Entry point address: 0x400470
Start of program headers: 64 (bytes into file)
Start of section headers: 4488 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 26
This peculiar error message happens when the dynamic loader required by a particular executable is missing.
You can find out the name of the dynamic loader that you need by applying readelf to the problem executable. On my x86-64 Linux box, for example
$ readelf -l /bin/ls | grep 'program interpreter'
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
("program interpreter" is another name for "dynamic loader".)
So, run the above command on your crosscomp binary on your development box. (If you don't have readelf or you get error messages, try arm-linux-gnueabi-readelf.) The file named after "program interpreter:" needs to exist on your target ARM machine. If you don't know where to get it, please post the output of the above command + ls -l of the directory that should have the missing file in it.

How elf file loaded correct memory address and executed successfully?

As I know basic difference between bin and elf that
Bin file contain only bit or bytes of data and you need to give address of memory when you load it in memory,
while in case of elf it have symbol look-ups and relocatable table, so no need to give address when you program it.
Now see attached image. I am using LPCexpresso to program elf file in device. if you not give base address then it will take 0x00000000 by default. Now i first programme bootloader.elf and then main.elf. in both case I am not giving base address.
Now my question is if I am not giving address then how elf file decide to program correct location and after programming one image if I programme another image then isn't it overwrite first one? (because in both case we haven't give address and by default it 0x00000000)
Normally this information is inside the ELF file created by the linker script.
As part of the GNU binutils, there is a tool called "readelf", that shows information about the ELF sections and headers. Unfortunatelly these tools uses to have a prefix depending on its configuration tool, most likely it will be called "arm-none-readelf". If you do not have it, checkout http://www.yagarto.org/
So, if you type "arm-none-readelf main.elf -a" it should show something like:
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: YOUR ARCHITECTURE
Version: 0x1
Entry point address: YOUR ENTRY ADDRESS
Start of program headers: 52 (bytes into file)
Start of section headers: YOUR SIZE
Flags: 0x300
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 36
Size of section headers: 40 (bytes)
Number of section headers: 55
Section header string table index: 52
(Please note that this is just example data).
Normally in all the compiler there are options for the linker that allows to specify the load address of your ELF, (uses to be called .ld file).
Hope it helps.

Identical (almost) ELF headers but executables won't run on each other's system

I'm trying to compile a couple of programs for a little embedded device I own. It's a Little-endian MIPS (mipsel) processor. I retrieved this executable from it via telnet and the builtin ftp client:
root#debian-mipsel:/home/user/wansview/devel# readelf -h unzip1
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: MIPS R3000
Version: 0x1
Entry point address: 0x401cc0
Start of program headers: 52 (bytes into file)
Start of section headers: 169960 (bytes into file)
Flags: 0x10001007, noreorder, pic, cpic, o32, mips2
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 6
Size of section headers: 40 (bytes)
Number of section headers: 24
Section header string table index: 23
root#debian-mipsel:/home/user/wansview/devel# file unzip1
unzip1: ELF 32-bit LSB executable, MIPS, MIPS-II version 1 (SYSV), dynamically linked (uses shared libs), stripped
I then downloaded the MIPSEL version of Debian and I'm running it in QEMU. When I run the retrieved program above I get:
root#debian-mipsel:/home/user/wansview/devel# ./unzip1
-bash: ./unzip1: No such file or directory
Which I understand means it's not the right platform. Stubbornly I compiled a little hello world nonetheless to compare the ELF and file info. My hello world runs fine in Debian MIPSEL but also returns No such file or directory on the embedded device. It's readelf and file output is strikingly similar though:
root#debian-mipsel:/home/user/wansview/devel# readelf -h hello
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: MIPS R3000
Version: 0x1
Entry point address: 0x400740
Start of program headers: 52 (bytes into file)
Start of section headers: 3652 (bytes into file)
Flags: 0x10001005, noreorder, cpic, o32, mips2
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 10
Size of section headers: 40 (bytes)
Number of section headers: 36
Section header string table index: 35
root#debian-mipsel:/home/user/wansview/devel# file hello
hello: ELF 32-bit LSB executable, MIPS, MIPS-II version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xeb3877062337a3dfd15cc09305691685ac0e8c57, with unknown capability 0xf41 = 0x756e6700, with unknown capability 0x70100 = 0x1040000, stripped
I'm trying to better understand how my two systems differ and why the executables won't run on both. Are there any flags I could add to gcc to successfully compile for the embedded device?
More info about the device
# cat /proc/cpuinfo
system type : Ralink SoC
processor : 0
cpu model : MIPS 24K V4.12
BogoMIPS : 239.10
wait instruction : yes
microsecond timers : yes
tlb_entries : 32
extra interrupt vector : yes
hardware watchpoint : yes
ASEs implemented : mips16 dsp
VCED exceptions : not available
VCEI exceptions : not available
More info about Debian MIPSEL
(Binaries compiled on debian-mipsel won't run on the target embedded device)
root#debian-mipsel:/home/user/wansview/devel# cat /proc/cpuinfo
system type : MIPS Malta
processor : 0
cpu model : MIPS 24Kc V0.0 FPU V0.0
BogoMIPS : 1038.33
wait instruction : yes
microsecond timers : yes
tlb_entries : 16
extra interrupt vector : yes
hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8]
ASEs implemented : mips16
shadow register sets : 1
kscratch registers : 0
core : 0
VCED exceptions : not available
VCEI exceptions : not available
More info about Aboriginal Linux Mipsel
(Binaries compiled on Aboriginal Linux will run on the embedded device, and it can run binaries retrieved from the device. I'm not happy with it as it doesn't have make and other tools I need for compiling larger applications)
(mipsel:1) /home/wansview # cat /proc/cpuinfo
system type : MIPS Malta
machine : Unknown
processor : 0
cpu model : MIPS 24Kc V0.0 FPU V0.0
BogoMIPS : 1013.76
wait instruction : yes
microsecond timers : yes
tlb_entries : 16
extra interrupt vector : yes
hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8]
isa : mips1 mips2 mips32r1 mips32r2
ASEs implemented : mips16
shadow register sets : 1
kscratch registers : 0
core : 0
VCED exceptions : not available
VCEI exceptions : not available
LDD
Here's a screenshot with ldd ran against my hello world and against unzip1 on both aboriginal linux and debian mipsel. Aboriginal Linux runs applications retrieved from the device just fine, and if I compile under Aboriginal Linux I can run the resulting binary on the embedded device. The reason I'm not content with Aboriginal is that doesn't have GNU make and other useful tools for larger applications, and no easy way to get them there.
You clearly need a different toolchain. On your Debian-mipsel, your toolchain uses glibc while your target uses uClibc.
So, maybe you would like to generate it by yourself using Buildroot:
wget http://buildroot.uclibc.org/downloads/buildroot-2014.11.tar.gz
tar zxf http://buildroot.uclibc.org/downloads/buildroot-2014.11.tar.gz
cd buildroot-2014.11
A trick to preconfigure for mipsel, R1 without soft-float (my will, check yours):
cat <<_EOF > .config
BR2_HAVE_DOT_CONFIG=y
BR2_mipsel=y
BR2_ARCH="mipsel"
BR2_ENDIAN="LITTLE"
BR2_GCC_TARGET_ARCH="mips32"
BR2_GCC_TARGET_ABI="32"
BR2_ARCH_HAS_ATOMICS=y
BR2_mips_32=y
# BR2_MIPS_SOFT_FLOAT is not set
BR2_MIPS_OABI32=y
_EOF
Finish your choice in Buildroot menuconfig, but you can
also keep it like this with save and exit.
make menuconfig # tweak options at your will,
make -j8 # takes 8 minutes on my machine
Then, your compiler can be found in ./output/host/usr/bin
A real example:
echo '#include <stdio.h>
int main(int argc, char* argv[]) {
printf("Hello World.\n");
return 0;
}' > hello.c
And compile it with your brand-new uClibc GCC compiler
output/host/usr/bin/mipsel-buildroot-linux-uclibc-gcc -o hello hello.c
A glimpse into the hello program: (didn't had time to fix my ldd...)
$ file hello
hello: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
$ strings hello | grep "lib.*so*"
/lib/ld-uClibc.so.0
libgcc_s.so.1
libc.so.0
It's done with the toolchain and compile your program.
Now that you have time :-) see what Buildroot offers :
a complete distribution (in output/target/) for embedded systems in many architectures.
EDIT: Better chance to execute
You can statically link your program in order to maximize the chances to run your code on any target.
$ output/host/usr/bin/mipsel-linux-gcc -Wall -o hello -static hello.c
$ file ./hello
./hello: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
And now, as that static version doesn't depend anymore on any external lib (only uClibc, here), this MIPS executable can even run on my x86_64 machine (thanks to binfmt and Qemu) :
$ uname -mo
x86_64 GNU/Linux
$ ./hello
Hello World.
Cheers.
Maybe i'm wrong but a simple fix (but not elegant way) in such cases could be to link the missing files to the existing ones:
ln -s /lib/libc.so.6 /lib/libc.so.0
like in this situation:
https://dev.openwrt.org/ticket/3083

How to use cross gdb to examine core file from crosstarget machine

I have a core file from embedded SH3 linux device, and gdb of the cross compiler environment (sh3-linux-gdb) in my host linux.
But I have problems loading the core file with gdb:
$ sh3-linux-gdb ./myprogram ./core
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
...
This GDB was configured as "--host=i386-pc-linux-gnu --target=sh3-linux"...
GDB can't read core files on this machine.
(gdb)
Why it can't read the core file?
Is there any way to read the core file from target system to the cross gdb?
There is gdbserver in target machine (SH3-linux), but not gdb itself.
I am able to do runtime debuging of processes of target machine with gdbserver and sh3-linux-gdb, so sh3-linux-gdb should be correctly compiled.
EDIT:
readelf dump was requested:
[build]$ sh3-linux-readelf -a core
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: CORE (Core file)
Machine: Renesas / SuperH SH
Version: 0x1
Entry point address: 0x0
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: 51
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
There are no sections in this file.
There are no sections in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
NOTE 0x000694 0x00000000 0x00000000 0x00200 0x00000 0
LOAD 0x001000 0x00400000 0x00000000 0x00000 0x01000 R E 0x1000
----- several boring lines removed -----
LOAD 0x05a000 0x29952000 0x00000000 0x01000 0x01000 RW 0x1000
LOAD 0x05b000 0x7be48000 0x00000000 0x15000 0x15000 RWE 0x1000
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.
Notes at offset 0x00000694 with length 0x00000200:
Owner Data size Description
CORE 0x000000a8 NT_PRSTATUS (prstatus structure)
CORE 0x0000007c NT_PRPSINFO (prpsinfo structure)
CORE 0x000000a0 NT_AUXV (auxiliary vector)
[build]$
EDIT2: Same problem with --core option:
$ sh3-linux-gdb ./myprogram --core=./core
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "--host=i386-pc-linux-gnu --target=sh3-linux"...RUN GDB INIT
GDB can't read core files on this machine.
(gdb)
Try according to http://forums.freescale.com/t5/68K-ColdFire-reg-Microprocessors/GDB-can-t-read-core-files/td-p/70181
sh3-linux-gdb ./myprogram --core=./core
It may be a bug in the old gdb http://sourceware.org/bugzilla/show_bug.cgi?id=9542 - so try newer gdb (7) too.
Also possible that core was dumped in unsupported format. What is target's OS, version?
Can you post the output or readelf -a core ?
It is possible to debug your application, not with gdb directly but with gdb server. The first thing you have to do is to call gdbserver in the target system (you said in your question that this package is already installed) :
gdbserver AAA.BBB.CCC.DDD:port ./myprogram
It is assume that the target machine is accessible to an IP address : AAA.BBB.CCC.DDD:port. Once, you have done that, you can call gdb in your development machine by specifying the target remote server :
% gdb ./myprogram
% [...]
(gdb) target remote AAA.BBB.CCC.DDD:port
Note that the target remote server IP address are the same of the gdbserver.

Resources