Page 1 of 2

ELF section and program headers

Posted: Thu Feb 07, 2008 7:20 am
by StephanvanSchaik
Hello,

I am programming my bootsector and I am busy with the ELF parsing, at the wiki they say that only the program headers are important, so my question is are the section headers needed for the ELF parsing in a bootsector or can I leave that part out? They also talk about the program headers but there's only one offset in the ELF header, here my question is? Are the program headers after each other like this:

| Program header 1 |
| Program header 2 |
| Program header 3 |

Or are they all spread around over the ELF file? I was thinking the first but I am not sure...


Thanks already,
Stephan van Schaik.

Posted: Thu Feb 07, 2008 7:34 am
by JamesM
Hi,

The program headers are all contiguous - an offset to the start of the array of program headers is available in the ELF header.

Personally I have never ever used program headers - I've only used section headers (which are the useful ones which tell you where the .text, .data etc sections are).

Posted: Thu Feb 07, 2008 7:47 am
by StephanvanSchaik
Thanks, James.

Yesterday I was confused because they keep talking about sections on the wiki and at the end they say that you need to use the program headers. Anyway thanks for clearing it up.

Posted: Thu Feb 07, 2008 7:51 am
by jal
StephanVanSchaik wrote:Thanks, James.

Yesterday I was confused because they keep talking about sections on the wiki and at the end they say that you need to use the program headers. Anyway thanks for clearing it up.
You need the program header to know where the section headers are. Unless you use GRUB, which doesn't give you the program header, but instead the fields from the program header that indicate where to find the section headers.


JAL

Posted: Thu Feb 07, 2008 7:59 am
by AJ
Hi,

I always understoor that you use the program headers to relocate a statically linked program binary which is linked position-dependently - at least, that's what my boot loader does.

Cheers,
Adam

Posted: Thu Feb 07, 2008 9:47 am
by JamesM
jal wrote:
StephanVanSchaik wrote:Thanks, James.

Yesterday I was confused because they keep talking about sections on the wiki and at the end they say that you need to use the program headers. Anyway thanks for clearing it up.
You need the program header to know where the section headers are. Unless you use GRUB, which doesn't give you the program header, but instead the fields from the program header that indicate where to find the section headers.


JAL
Possibly a nomenclature clash here - the "one true header", the one at the start of the ELF file, I referred to as the "ELF header". The "program headers" he referred to were, I assumed, the "process headers" detailed in the ELF man pages.

Posted: Thu Feb 07, 2008 10:08 am
by StephanvanSchaik
In the ELF specification I got, they don't talk about process headers :?. I so far know how to handle the ELF header, where in you can find how much program headers you have, how big they are and where they start in the file, the same with section headers.
typedef struct {
unsigned char e_ident[EI_NIDENT];
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;
} Elf32_Ehdr;
The only problem I've got is that I don't know if I need to use the program header(s) or/and the section header(s).

Program header table entry:
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
Section header table entry:
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
Hopefully this clears up a few things about the headers...

Posted: Thu Feb 07, 2008 10:15 am
by AJ
Those are exactly the headers I use (and their 64 bit equivalents). I currently use program headers for statically linked program relocation with no problems.

Cheers,
Adam

Posted: Thu Feb 07, 2008 11:24 am
by StephanvanSchaik
Using readelf, I see that there are 3 program headers. I also found this back in elf.h of GeekOS as stated in the wiki. If I am right this is the max. possible... The first is then text, the second data but I don't know what the third is. Is this bss? If so, does it need to be even handled then since it's just empty.

If I am right, I just should read out the program header, reallocate them in memory and then just execute it. Correct me if I am wrong.

Posted: Thu Feb 07, 2008 11:29 am
by AJ
Hi,

I believe that it will be a .bss. In this case, it needs to be zeroed as this is what your program will expect. There is also a chance that uninitialised data can appear in any of the sections. In this case, you will find that p_memsz is greater than p_filesz. In this case, you copy over p_filesz bytes and then zero a range of (p_memsz - p_filesz) bytes.

Is your third section marked with PT_LOAD? I suggest looking through the elf reference and implement the proper relocation method for all possible program header types (there aren't many!).

Cheers,
Adam

Posted: Thu Feb 07, 2008 11:38 am
by StephanvanSchaik
ReadELF returns the following type for the third program header:
LOOS+474e551
That doesn't seem to be a ptype :?. The second program header seems to be both data and bss. The first program header seems to be text so I got actually no idea what the third one is or what it is used for...

Posted: Fri Feb 08, 2008 2:37 am
by JamesM
AJ wrote:Hi,

I believe that it will be a .bss. In this case, it needs to be zeroed as this is what your program will expect. There is also a chance that uninitialised data can appear in any of the sections. In this case, you will find that p_memsz is greater than p_filesz. In this case, you copy over p_filesz bytes and then zero a range of (p_memsz - p_filesz) bytes.

Is your third section marked with PT_LOAD? I suggest looking through the elf reference and implement the proper relocation method for all possible program header types (there aren't many!).

Cheers,
Adam
What?! .bss, .text, et al. Are sections. They therefore are defined by section headers!

Pull the section headers list out, find the section header string table index (sh_shstrndx), use that to look up the names of all the sections. You'll end up with things like .text, .bss, .symtab, .strtab etc. Then use the flags field in the section header of each of those to discover if they need memory allocating, and where, and if they need that memory zeroing (like .bss) or copying from the file (like .text).


PS: AJ: Sorry if what you said was correct, I've never really used process headers, but .text et al are definately sections ;)

Posted: Fri Feb 08, 2008 3:07 am
by AJ
Sorry, JamesM, I was being ambiguous in my use of the word sections. Once I started talking about program headers, I then started referring to each program header as a 'section' - this is clearly wrong and I should have avoided that nomenclature!

My ELF relocation code runs like this, for what it's worth:

Code: Select all

void exe_relocate_elf(void *elfstart)
{
	Elf32_Ehdr *ehead = (Elf32_Ehdr *)elfstart;
	Elf32_Phdr *phead = (Elf32_Phdr*)((u32)ehead + ehead->e_phoff);
	
	for(u32 i=0;i<ehead->e_phnum;i++)
	{
		if(phead[i].p_type == PT_LOAD)
		{
			memcpy((void*)phead[i].p_vaddr, (void*)(mod->mod_start + phead[i].p_offset), phead[i].p_filesz);
			memset((void*)(phead[i].p_vaddr + phead[i].p_filesz), 0, phead[i].p_memsz - phead[i].p_filesz);
		}
	}
}
Which is fairly simple, really. Obviously you also need to do checks to ensure that this is a valid ELF file, you need to page in any RAM needed initially and you need to read the entry point from the ELF header.

[EDIT]
Oh, and what I meant about the BSS:
In the program headers, the BSS will not be identified as such, but it may appear in one of two ways. Either it will appear as a separate program header with p_filesz == 0 and p_memsz == bss size, OR it will appear
as an over sized code / data program header (p_memsz > p_filesz).
[/EDIT]

Cheers,
Adam

Posted: Fri Feb 08, 2008 3:54 am
by JamesM
Very interesting. So program headers give the same information as section headers? Why are they duplicated?

Posted: Fri Feb 08, 2008 5:02 am
by jal
JamesM wrote:Then use the flags field in the section header of each of those to discover if they need memory allocating, and where, and if they need that memory zeroing (like .bss) or copying from the file (like .text).
So what exactly are the rules for zeroing? I noticed that Grub zeroes any section with type SHT_NOBITS and flags SHF_ALLOC, which I find rather annoying (I'd like initial sections for stack and heap so I don't need to determine myself where to put them, but it takes quite some time to zero the memory).


JAL