Linux ELF Loading

From Ggl's wiki

Jump to: navigation, search

Contents

Loading

Static

  • All PT_LOAD segements are mapped into memory at the correct locations (p_vaddr)
  • Needed libraries are also loaded
  • Needed relocations are performed
  • Control is transfered to the main executable entry point by setting the pc (program counter) to the Elf header's entry point (e_entry)
  • The stack is initialized

Dynamic

  • The dynamic linker (usually /lib/ld-linux.so.2) is mapped into memory
  • If PT_INTERP exists the pc is set to the entry point of the program interpreter
  • The stack is initialized

Stack state

positioncontentsize (bytes) + comment
stack pointer -> [ argc = number of args ]4
[ argv[0] (pointer) ]4 (program name)
[ argv[1] (pointer) ]4
[ argv[..] (pointer) ]4 * x
[ argv[n - 1] (pointer) ]4
[ argv[n] (pointer) ]4 (= NULL)
[ envp[0] (pointer) ]4
[ envp[1] (pointer) ]4
[ envp[..] (pointer) ]4
[ envp[term] (pointer) ]4 (= NULL)
[ auxv[0] (Elf32_auxv_t) ]8
[ auxv[1] (Elf32_auxv_t) ]8
[ auxv[..] (Elf32_auxv_t) ]8
[ auxv[term] (Elf32_auxv_t) ]8 (= AT_NULL vector)
[ padding ]0 - 16
[ argument ASCIIZ strings ] >= 0
[ environment ASCIIZ str. ] >= 0
(0xbffffffc)[ end marker ]4 (= NULL)
(0xc0000000)< top of stack >0 (virtual)

Details

(from /usr/src/linux-`uname -r`/fs/binfmt_elf.c

Useful usual kernel functions to know:

kmalloc
kfree
kernel_read
set_brk

The main kernel function which loads an elf binary is load_elf_binary.

It works mainly on this structure :


	struct {
		struct elfhdr elf_ex;
		struct elfhdr interp_elf_ex;
  		struct exec interp_ex;
	} *loc;

It begins by getting the elf header of the binary file :

	/* Get the exec-header */
	loc->elf_ex = *((struct elfhdr *) bprm->buf);

and after do some consistency checks :

	/* First of all, some simple consistency checks */
	if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
		goto out;
 
	if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
		goto out;
	if (!elf_check_arch(&loc->elf_ex))
		goto out;
	if (!bprm->file->f_op||!bprm->file->f_op->mmap)
		goto out;

So, it checks the magic bytes (e_ident), the type of elf file (ET_EXEC is for an executable file, ET_DYN is a shared object file), the arch.

It continues by getting Program Header info :

/* Now read in all of the header information */

	retval = -ENOMEM;
	if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr))
		goto out;
	if (loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
		goto out;
	size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr);
	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);

and read program header into elf_phdata :

	retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, (char *) elf_phdata, size);

Now to parse the program it sets a pointer to it :

elf_ppnt = elf_phdata;

The phdr is parsed with this loop to find the PT_INTERP entry :

for (i = 0; i < loc->elf_ex.e_phnum; i++) {

           if (elf_ppnt->p_type == PT_INTERP) {
			/* This is the program interpreter used for
			 * shared libraries - for now assume that this
			 * is an a.out format binary
			 */

           [...]
                       /* Get the exec headers */
			loc->interp_ex = *((struct exec *) bprm->buf);
			loc->interp_elf_ex = *((struct elfhdr *) bprm->buf);
			break;
           }
           elf_ppnt++;
       }

Checks if it has PT_GNU_STACK :

elf_ppnt = elf_phdata;

	for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
		if (elf_ppnt->p_type == PT_GNU_STACK) {
			if (elf_ppnt->p_flags & PF_X)
				executable_stack = EXSTACK_ENABLE_X;
			else
				executable_stack = EXSTACK_DISABLE_X;
			break;
		}
 	have_pt_gnu_stack = (i < loc->elf_ex.e_phnum);

Useful C structures (32 bits)

(from /usr/include/elf.h)

The ELF file header

(This appears at the start of every ELF file)

#define EI_NIDENT (16)
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;

/* Fields in the e_ident array. The EI_* macros are indices into the array. The macros under each EI_* macro are the values the byte may have. */

#define EI_MAG0		0		/* File identification byte 0 index */
#define ELFMAG0		0x7f		/* Magic number byte 0 */

#define EI_MAG1		1		/* File identification byte 1 index */
#define ELFMAG1		'E'		/* Magic number byte 1 */

#define EI_MAG2		2		/* File identification byte 2 index */
#define ELFMAG2		'L'		/* Magic number byte 2 */

#define EI_MAG3		3		/* File identification byte 3 index */
#define ELFMAG3		'F'		/* Magic number byte 3 */

/* Conglomeration of the identification bytes, for easy testing as a word. */

#define	ELFMAG		"\177ELF"
#define	SELFMAG		4

#define EI_CLASS	4		/* File class byte index */
#define ELFCLASSNONE	0		/* Invalid class */
#define ELFCLASS32	1		/* 32-bit objects */
#define ELFCLASS64	2		/* 64-bit objects */
#define ELFCLASSNUM	3
 
#define EI_DATA	5		/* Data encoding byte index */
#define ELFDATANONE	0		/* Invalid data encoding */
#define ELFDATA2LSB	1		/* 2's complement, little endian */
#define ELFDATA2MSB	2		/* 2's complement, big endian */
#define ELFDATANUM	3

#define EI_VERSION	6		/* File version byte index */
					/* Value must be EV_CURRENT */

#define EI_OSABI	7		/* OS ABI identification */
#define ELFOSABI_NONE	0	/* UNIX System V ABI */
#define ELFOSABI_SYSV	0	/* Alias.  */

#define ELFOSABI_NETBSD	2	/* NetBSD.  */
#define ELFOSABI_LINUX		3	/* Linux.  */
#define ELFOSABI_SOLARIS	6	/* Sun Solaris.  */

#define ELFOSABI_FREEBSD	9	/* FreeBSD.  */
#define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
#define ELFOSABI_ARM		97	/* ARM */
#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */

#define EI_ABIVERSION	8		/* ABI version */

#define EI_PAD		9		/* Byte index of padding bytes */

/* Legal values for e_type (object file type). */

#define ET_NONE	0		/* No file type */
#define ET_REL		1		/* Relocatable file */
#define ET_EXEC	2		/* Executable file */
#define ET_DYN		3		/* Shared object file */
#define ET_CORE	4		/* Core file */
#define ET_NUM		5		/* Number of defined types */
#define ET_LOOS	0xfe00		/* OS-specific range start */
#define ET_HIOS	0xfeff		/* OS-specific range end */
#define ET_LOPROC	0xff00		/* Processor-specific range start */
#define ET_HIPROC	0xffff		/* Processor-specific range end */

/* Legal values for e_machine (architecture). */

#define EM_NONE	 0		/* No machine */
#define EM_M32		 1		/* AT&T WE 32100 */
#define EM_SPARC	 2		/* SUN SPARC */
#define EM_386		 3		/* Intel 80386 */
#define EM_68K		 4		/* Motorola m68k family */
#define EM_88K		 5		/* Motorola m88k family */
#define EM_860		 7		/* Intel 80860 */
#define EM_MIPS	 8		/* MIPS R3000 big-endian */
#define EM_S370	 9		/* IBM System/370 */
#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */

#define EM_PPC		20		/* PowerPC */
#define EM_PPC64	21		/* PowerPC 64-bit */

#define EM_ARM		40		/* ARM */
#define EM_FAKE_ALPHA	41		/* Digital Alpha */
#define EM_SH		42		/* Hitachi SH */

#define EM_COLDFIRE	52		/* Motorola Coldfire */
#define EM_68HC12	53		/* Motorola M68HC12 */

Section Header

typedef struct
{
  Elf32_Word	sh_name;		/* Section name (string tbl index) */
  Elf32_Word	sh_type;		/* Section type */
  Elf32_Word	sh_flags;		/* Section flags */
  Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
  Elf32_Off	sh_offset;		/* Section file offset */
  Elf32_Word	sh_size;		/* Section size in bytes */
  Elf32_Word	sh_link;		/* Link to another section */
  Elf32_Word	sh_info;		/* Additional section information */
  Elf32_Word	sh_addralign;		/* Section alignment */
  Elf32_Word	sh_entsize;		/* Entry size if section holds table */
} Elf32_Shdr;

Symbol table entry

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;

Relocation table entry

(without addend (in section of type SHT_REL)

typedef struct
{
  Elf32_Addr	r_offset;		/* Address */
  Elf32_Word	r_info;			/* Relocation type and symbol index */
} Elf32_Rel;

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;

/* Legal values for p_type (segment type). */

#define PT_NULL	0		/* Program header table entry unused */
#define PT_LOAD	1		/* Loadable program segment */
#define PT_DYNAMIC	2		/* Dynamic linking information */
#define PT_INTERP	3		/* Program interpreter */
#define PT_NOTE	4		/* Auxiliary information */
#define PT_SHLIB	5		/* Reserved */
#define PT_PHDR	6		/* Entry for header table itself */
#define PT_TLS		7		/* Thread-local storage segment */
#define PT_NUM		8		/* Number of defined types */
#define PT_LOOS	0x60000000	/* Start of OS-specific */
#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
#define PT_LOSUNW	0x6ffffffa
#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
#define PT_HISUNW	0x6fffffff
#define PT_HIOS	0x6fffffff	/* End of OS-specific */
#define PT_LOPROC	0x70000000	/* Start of processor-specific */
#define PT_HIPROC	0x7fffffff	/* End of processor-specific */

/* Legal values for p_flags (segment flags). */

#define PF_X		(1 << 0)	/* Segment is executable */
#define PF_W		(1 << 1)	/* Segment is writable */
#define PF_R		(1 << 2)	/* Segment is readable */
#define PF_MASKOS	0x0ff00000	/* OS-specific */
#define PF_MASKPROC	0xf0000000	/* Processor-specific */
typedef struct
{
  Elf32_Sword	d_tag;			/* Dynamic entry type */
  union
    {
      Elf32_Word d_val;			/* Integer value */
      Elf32_Addr d_ptr;			/* Address value */
    } d_un;
} Elf32_Dyn;

Auxiliary vector

/* This vector is normally only used by the program interpreter. The usual definition in an ABI supplement uses the name auxv_t. The vector is not usually defined in a standard <elf.h> file, but it can't hurt. We rename it to avoid conflicts. The sizes of these types are an arrangement between the exec server and the program interpreter, so we don't fully specify them here. */

typedef struct
{
  int a_type;			/* Entry type */
  union
    {
      long int a_val;		/* Integer value */
      void *a_ptr;		/* Pointer value */
      void (*a_fcn) (void);	/* Function pointer value */
    } a_un;
} Elf32_auxv_t;

/* Legal values for a_type (entry type). */

#define AT_NULL	0		/* End of vector */
#define AT_IGNORE	1		/* Entry should be ignored */
#define AT_EXECFD	2		/* File descriptor of program */
#define AT_PHDR	3		/* Program headers for program */
#define AT_PHENT	4		/* Size of program header entry */
#define AT_PHNUM	5		/* Number of program headers */
#define AT_PAGESZ	6		/* System page size */
#define AT_BASE	7		/* Base address of interpreter */
#define AT_FLAGS	8		/* Flags */
#define AT_ENTRY	9		/* Entry point of program */
#define AT_NOTELF	10		/* Program is not ELF */
#define AT_UID		11		/* Real uid */
#define AT_EUID	12		/* Effective uid */
#define AT_GID		13		/* Real gid */
#define AT_EGID	14		/* Effective gid */
#define AT_CLKTCK	17		/* Frequency of times() */
Personal tools