Update markdown and tabs and stuff

This commit is contained in:
2016-10-22 17:07:50 +02:00
parent 67e817490e
commit a27daafa0a
39 changed files with 2249 additions and 2139 deletions

View File

@@ -10,23 +10,24 @@ where to find everything. It has the following structure. The
[ELF specification](http://www.skyfree.org/linux/references/ELF_Format.pdf)
gives an excellent description on the meaning and use of each field.
typedef struct
{
uint8_t identity[16];
uint16_t type;
uint16_t machine;
uint32_t version;
uint32_t entry;
uint32_t ph_offset;
uint32_t sh_offset;
uint32_t flags;
uint16_t header_size;
uint16_t ph_size;
uint16_t ph_num;
uint16_t sh_size;
uint16_t sh_num;
uint16_t strtab_index;
}__attributes__((packed)) elf_header;
:::c
typedef struct
{
uint8_t identity[16];
uint16_t type;
uint16_t machine;
uint32_t version;
uint32_t entry;
uint32_t ph_offset;
uint32_t sh_offset;
uint32_t flags;
uint16_t header_size;
uint16_t ph_size;
uint16_t ph_num;
uint16_t sh_size;
uint16_t sh_num;
uint16_t strtab_index;
}__attributes__((packed)) elf_header;
The first thing we should do is check whether we actually got an
executable ELF file. (In the following code, I'll assume the entire elf
@@ -38,31 +39,33 @@ identity field. The first four bytes of this filed should always be
`0x7F`,`'E'`,`'L'`,`'F'`. If that's correct, we can look at the `type`
field. For an executable standalone program, this should be `2`.
int load_elf(uint8_t *data)
{
elf_header *elf = (elf_header *)data;
if(is_elf(elf) != ELF_TYPE_EXECUTABLE)
return -1;
...
:::c
int load_elf(uint8_t *data)
{
elf_header *elf = (elf_header *)data;
if(is_elf(elf) != ELF_TYPE_EXECUTABLE)
return -1;
...
`is_elf` looks as follows. Note the use of `strncmp` which I can do
because I link [newlib into my kernel](/blog/2013/08/Catching-Up/).
int is_elf(elf_header *elf)
{
int iself = -1;
if((elf->identity[0] == 0x7f) && \
!strncmp((char *)&elf->identity[1], "ELF", 3))
{
iself = 0;
}
if(iself != -1)
iself = elf->type;
return iself;
}
:::c
int is_elf(elf_header *elf)
{
int iself = -1;
if((elf->identity[0] == 0x7f) && \
!strncmp((char *)&elf->identity[1], "ELF", 3))
{
iself = 0;
}
if(iself != -1)
iself = elf->type;
return iself;
}
Should be pretty straight forward. Let's continue.
@@ -70,35 +73,37 @@ For just loading a simple ELF program, we only need to look at the
program headers which are located in a table at offset `ph_offset` in
the file.
typedef struct
{
uint32_t type;
uint32_t offset;
uint32_t virtual_address;
uint32_t physical_address;
uint32_t file_size;
uint32_t mem_size;
uint32_t flags;
uint32_t align;
}__attributes__((packed)) elf_phead;
:::c
typedef struct
{
uint32_t type;
uint32_t offset;
uint32_t virtual_address;
uint32_t physical_address;
uint32_t file_size;
uint32_t mem_size;
uint32_t flags;
uint32_t align;
}__attributes__((packed)) elf_phead;
The program headers each tell us about one section of the file, and we
use them to find out what parts of the elf image should be loaded where
in memory. So, the next step would be to go through all program headers
looking for loadable sections and load them into memory.
...
elf_phead *phead = (elf_phead)&data[elf->ph_offset];
uint32_t i;
for(i = 0; i < elf->ph_num; i++)
{
if(phead[i].type == ELF_PT_LOAD)
{
load_elf_segment(data, &phead[i]);
}
}
return 0;
}
:::c
...
elf_phead *phead = (elf_phead)&data[elf->ph_offset];
uint32_t i;
for(i = 0; i < elf->ph_num; i++)
{
if(phead[i].type == ELF_PT_LOAD)
{
load_elf_segment(data, &phead[i]);
}
}
return 0;
}
This would also be a good time to update the memory manager information
about the executable. You might want to keep track of the start and end
@@ -106,25 +111,26 @@ of code and data for example.
Anyway, `load_elf_segment()` looks like this
void load_elf_segment(uint8_t *data, elf_phead *phead)
{
uint32_t memsize = phead->mem_size; // Size in memory
uint32_t filesize = phead->file_size; // Size in file
uint32_t mempos = phead->virtual_address; // Offset in memory
uint32_t filepos = phead->offset; // Offset in file
:::c
void load_elf_segment(uint8_t *data, elf_phead *phead)
{
uint32_t flags = MM_FLAG_READ;
if(phead->flags & ELF_PT_W) flags |= MM_FLAG_WRITE;
uint32_t memsize = phead->mem_size; // Size in memory
uint32_t filesize = phead->file_size; // Size in file
uint32_t mempos = phead->virtual_address; // Offset in memory
uint32_t filepos = phead->offset; // Offset in file
new_area(current->proc, mempos, mempos + memsize, \
flags, MM_TYPE_DATA);
uint32_t flags = MM_FLAG_READ;
if(phead->flags & ELF_PT_W) flags |= MM_FLAG_WRITE;
if(memsize == 0) return;
new_area(current->proc, mempos, mempos + memsize, \
flags, MM_TYPE_DATA);
memcpy(mempos, &data[filepos], filesize);
memset(mempos + filesize, 0, memsize - filesize);
}
if(memsize == 0) return;
memcpy(mempos, &data[filepos], filesize);
memset(mempos + filesize, 0, memsize - filesize);
}
Let's go through it.