Why is the program header executable? - linux

I used readelf on several binaries on my linux box and saw something that surprised me in the program headers. This eample is from the 'ld' utility, but it also occurs with anything I compile with gcc.
PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
This segment spans the entirety of the program headers. Why is is marked as executable? It doesn't contain machine code. But also, why is even this present in the headers? I don't really want it in my program image.

The PHDR pointing to the PHDRs tells the loader that the PHDRs themselves should be mapped to the process address space, in order to make them accessible to the program itself.
This is useful mainly for dynamic linking.
The reason the memory is marked as executable is because the PHDRs are smaller than one page, and live right next to the start of the executable code. If the permissions for the PHDRs were different from those of the program text, the linker would have to insert padding between them.

The main File ELF headers are there to easily find the offset in the file where other sections are stored. Then each subheader describes the data in it's section.
Main ELF header looks like this:
/* ELF File Header */
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
The program header(s) are there because they describe the executable parts of the ELF executable.
The next portion of the program are
the ELF program headers. These
describe the sections of the program
that contain executable program code
to get mapped into the program address
space as it loads.
/* Program segment header. */
typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;
This is taken from here

Related

How to evaluate the flags field of mtd_info_user?

The MTD driver placed inside the Linux kernel source has a definition as below.
struct mtd_info_user {
__u8 type;
__u32 flags;
__u32 size; /* Total size of the MTD */
__u32 erasesize;
__u32 writesize;
__u32 oobsize; /* Amount of OOB data per block (e.g. 16) */
__u64 padding; /* Old obsolete field; do not use */
};
I'm trying to understand what the flags field stands for. My ultimate purpose is to find a way to check if the external MTD device is healthy. I thought that the flags field can represent the actual status of the device.
Inside the mtdchar_open(..) function from mtdchar.c source code, there is a comparison as below.
/* You can't open it RW if it's not a writeable device */
if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
ret = -EACCES;
goto out1;
}
So, I guess the flags field can be evaluated by using the macros from the mtd-abi.h header.
#define MTD_ABSENT 0
#define MTD_RAM 1
#define MTD_ROM 2
#define MTD_NORFLASH 3
#define MTD_NANDFLASH 4 /* SLC NAND */
#define MTD_DATAFLASH 6
#define MTD_UBIVOLUME 7
#define MTD_MLCNANDFLASH 8 /* MLC NAND (including TLC) */
#define MTD_WRITEABLE 0x400 /* Device is writeable */
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
#define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */
The problem is about why some of those definitions are declared like normal integers, e.g. MTD_ABSENT.

ELF Header, are offset 06h and 14h duplicated?

I would like to know if these 2 headers have the same meaning nor why?
From wikipedia :
offset 06h : Set to 1 for the original version of ELF.
offset 14h : Set to 1 for the original version of ELF.
reference : http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
You may want to read a more detailed document which is likely to include the information you're looking for:
http://www.skyfree.org/linux/references/ELF_Format.pdf
The header structure
#define EINIDENT 16
typedefstruct{
unsigned char e_ident[EINIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32Ehdr;
The 2nd e_version which defines the version as 1 (i.e. "current")
e_version This member identifies the object file version.
Name Value Meaning
EV_NONE 0 Invalid version
EV_CURRENT 1 Current version
The value 1 signifies the original file format; extensions will
create new versions with higher numbers. The value of EV_CURRENT,
though given as 1 above, will change as necessary to reflect the
current version number.
The version in the e_ident part is also EV_CURRENT, so exactly the same version:
EI_VERSION Byte e_ident[EI_VERSION] specifies the ELF header version
number. Currently, this value must be EV_CURRENT, as
explained above for e_version.
From what I understand, I would say that the version has not changed yet so it is still 1 in both places, but that could change in the future...

Difference between structures ttysize and winsize?

I have following code to get width and height of screen in Linux.
#ifdef TIOCGSIZE
struct ttysize ts;
ioctl(STDIN_FILENO, TIOCGSIZE, &ts);
cols = ts.ts_cols;
lines = ts.ts_lines;
#elif defined(TIOCGWINSZ)
struct winsize ts;
ioctl(STDIN_FILENO, TIOCGWINSZ, &ts);
cols = ts.ws_col;
lines = ts.ws_row;
#endif /* TIOCGSIZE */
What is difference between ttysize and winsize?
The ttysize was the original implementation for SunOS 3.0 (February 1986), and soon after made obsolete by winsize, which adds the size of the window in pixels. Here's
what the definitions look like in <sys/ttycom.h> from SunOS 4:
/*
* Window/terminal size structure.
* This information is stored by the kernel
* in order to provide a consistent interface,
* but is not used by the kernel.
*
* Type must be "unsigned short" so that types.h not required.
*/
struct winsize {
unsigned short ws_row; /* rows, in characters */
unsigned short ws_col; /* columns, in characters */
unsigned short ws_xpixel; /* horizontal size, pixels - not used */
unsigned short ws_ypixel; /* vertical size, pixels - not used */
};
#define TIOCGWINSZ _IOR(t, 104, struct winsize) /* get window size */
#define TIOCSWINSZ _IOW(t, 103, struct winsize) /* set window size */
/*
* Sun version of same.
*/
struct ttysize {
int ts_lines; /* number of lines on terminal */
int ts_cols; /* number of columns on terminal */
};
#define TIOCSSIZE _IOW(t,37,struct ttysize)/* set tty size */
#define TIOCGSIZE _IOR(t,38,struct ttysize)/* get tty size */
The data types are different (an integer would waste memory), and the fields have different names.
The ttysize structure has long been obsolete: if either is provided by the system, winsize is supported. That wasn't true when porting ncurses to SCO OpenServer in 1997, as noted in this chunk from lib_setup.c:
/*
* SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS,
* Solaris, IRIX) define TIOCGWINSZ and struct winsize.
*/
#ifdef TIOCGSIZE
# define IOCTL_WINSIZE TIOCGSIZE
# define STRUCT_WINSIZE struct ttysize
# define WINSIZE_ROWS(n) (int)n.ts_lines
# define WINSIZE_COLS(n) (int)n.ts_cols
#else
# ifdef TIOCGWINSZ
# define IOCTL_WINSIZE TIOCGWINSZ
# define STRUCT_WINSIZE struct winsize
# define WINSIZE_ROWS(n) (int)n.ws_row
# define WINSIZE_COLS(n) (int)n.ws_col
# endif
#endif
You might notice that Linux is not mentioned in the comment. According to comments in asm-sparc64/ioctls.h, the ioctl for ttysize was unsupported as of 2.6.16:
/* Note that all the ioctls that are not available in Linux have a
* double underscore on the front to: a) avoid some programs to
* think we support some ioctls under Linux (autoconfiguration stuff)
*/
...
#define TIOCCONS _IO('t', 36)
#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
#define TIOCGSOFTCAR _IOR('t', 100, int)
#define TIOCSSOFTCAR _IOW('t', 101, int)
#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
#define TIOCSWINSZ _IOW('t', 103, struct winsize)
#define TIOCGWINSZ _IOR('t', 104, struct winsize)
A much earlier comment in 1995 added the definitions (without the double-underscore). Possibly a few programs used that with Linux, although winsize was well established on most platforms before Linux was begun. A little more digging finds that the double-underscore was introduced in 1996 (patch-2.1.9 linux/include/asm-sparc/ioctls.h). Given that, very few programs would have used it with Linux.
Further reading:
Garbage-collect struct ttysize (OpenBSD mailing list)
/dev/console MKS manual page
They have the same function (at least in this case - maybe one structure has an additional field not used here).
Historically some (mainly older) Linux versions have different definitions of the IOCTL codes. Therefore some Linux versions have only TIOCGSIZE defined (using a ttysize structure) and some Linux versions have only TIOCGWINSZ defined.
Using the "#ifdef" construction the program can be compiled for both Linux versions.
Newer Linux versions should have both IOCTLs defined.

Where is Import Table in ELF file?

I found ".dynsym" in String Table, got index.
Then I found section with sh_name = index && sh_type = SHT_DYNSYM.
So I got sh_offset = 464 and sh_size = 64.
But you can see in the attached picture, that on the offset 464 there are only zeros.
I suppose that Import Table starts on offset 528. Question is: how calculate it %)
But you can see in the attached picture, that on the offset 464 there are only zeros.
Wrong: 01, 20, 29, 12 etc. are not "only zeros" last time I checked.
I suppose that Import Table starts on offset 528
No, it does not. For some reason you are expecting to find a Microsoft PE-style import table in an ELF file. It's not there.
An equivalent of an import table in ELF is contained in two tables. One contains Elf{32,64}_Sym fixed-size records:
typedef struct
{
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
} Elf32_Sym;
and is contained in the .dynsym section.
The other table is contained in .dynstr section (which, in your file starts at offset 528), and has just the (variable-size) strings separated by NUL character.
The .st_name in the first table refers to offset in .dynstr.

How to get the name of a segment by using its `Elf64_Phdr` program header?

As I know, a ELF object consists of a number of segments, each of which has a corresponding program header describing the segment. In libelf, a program header is defined as a Elf64_Phdr (or Elf32_Phdr) structure, and a Elf64_Phdr structure is defined like this:
typedef struct {
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;
However, segments have names (don't they?) and Elf64_Phdr structures don't have a field which points to their corresponding names. So, how to get a name of a segment of an ELF file from its corresponding program header? Or is the p_type field enough to identify a segment, so that segments don't have names?
However, segments have names (don't they?)
No, they don't.
Or is the p_type field enough to identify a segment, so that segments don't have names?
Correct.

Resources