/contrib/sdk/sources/newlib/pe/crtloader.c |
---|
0,0 → 1,223 |
#include <stdint.h> |
#include <stdio.h> |
#include <string.h> |
#include <alloca.h> |
#include <malloc.h> |
#include <setjmp.h> |
#include <envz.h> |
#include <kos32sys.h> |
#include "list.h" |
#include "pe.h" |
#define unlikely(x) __builtin_expect(!!(x), 0) |
//#define DBG(format,...) printf(format,##__VA_ARGS__) |
#define DBG(format,...) |
static inline void sec_copy(void *dst, void *src, size_t len) |
{ |
__asm__ __volatile__ ( |
"shrl $2, %%ecx \n\t" |
"rep movsl" |
: |
:"c"(len),"S"(src),"D"(dst) |
:"cc"); |
__asm__ __volatile__ ( |
"" |
:::"ecx","esi","edi"); |
}; |
void* load_libc(); |
static inline int IsPowerOf2(uint32_t val) |
{ |
if(val == 0) |
return 0; |
return (val & (val - 1)) == 0; |
} |
int validate_pe(void *raw, size_t raw_size) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
dos = (PIMAGE_DOS_HEADER)raw; |
if( !raw || raw_size < sizeof(IMAGE_DOS_HEADER) ) |
return 0; |
if( dos->e_magic != IMAGE_DOS_SIGNATURE || dos->e_lfanew <= 0) |
return 0; |
nt = MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); |
if( (uint32_t)nt < (uint32_t)raw) |
return 0; |
if(nt->Signature != IMAGE_NT_SIGNATURE) |
return 0; |
if(nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) |
return 0; |
if(nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) |
return 0; |
if(nt->OptionalHeader.SectionAlignment < 4096) |
{ |
if(nt->OptionalHeader.FileAlignment != nt->OptionalHeader.SectionAlignment) |
return 0; |
} |
else if(nt->OptionalHeader.SectionAlignment < nt->OptionalHeader.FileAlignment) |
return 0; |
if(!IsPowerOf2(nt->OptionalHeader.SectionAlignment) || |
!IsPowerOf2(nt->OptionalHeader.FileAlignment)) |
return 0; |
if(nt->FileHeader.NumberOfSections > 96) |
return 0; |
return 1; |
} |
void* create_image(void *raw) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
PIMAGE_SECTION_HEADER img_sec; |
void *img_base; |
uint32_t sec_align; |
int i; |
dos = (PIMAGE_DOS_HEADER)raw; |
nt = MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); |
img_base = user_alloc(nt->OptionalHeader.SizeOfImage); |
if(unlikely(img_base == NULL)) |
return 0; |
sec_copy(img_base, raw, nt->OptionalHeader.SizeOfHeaders); |
img_sec = MakePtr(PIMAGE_SECTION_HEADER, nt, sizeof(IMAGE_NT_HEADERS32)); |
sec_align = nt->OptionalHeader.SectionAlignment; |
for(i=0; i< nt->FileHeader.NumberOfSections; i++) |
{ |
void *src_ptr; |
void *dest_ptr; |
size_t sec_size; |
if ( img_sec->SizeOfRawData && img_sec->PointerToRawData ) |
{ |
src_ptr = MakePtr(void*, raw, img_sec->PointerToRawData); |
dest_ptr = MakePtr(void*, img_base, img_sec->VirtualAddress); |
sec_copy(dest_ptr, src_ptr, img_sec->SizeOfRawData); |
}; |
img_sec++; |
}; |
if(nt->OptionalHeader.DataDirectory[5].Size) |
{ |
PIMAGE_BASE_RELOCATION reloc; |
uint32_t delta = (uint32_t)img_base - nt->OptionalHeader.ImageBase; |
reloc = MakePtr(PIMAGE_BASE_RELOCATION, img_base, |
nt->OptionalHeader.DataDirectory[5].VirtualAddress); |
while ( reloc->SizeOfBlock != 0 ) |
{ |
uint32_t cnt; |
uint16_t *entry; |
uint16_t reltype; |
uint32_t offs; |
cnt = (reloc->SizeOfBlock - sizeof(*reloc))/sizeof(uint16_t); |
entry = MakePtr( uint16_t*, reloc, sizeof(*reloc) ); |
for ( i=0; i < cnt; i++ ) |
{ |
uint16_t *p16; |
uint32_t *p32; |
reltype = (*entry & 0xF000) >> 12; |
offs = (*entry & 0x0FFF) + reloc->VirtualAddress; |
switch(reltype) |
{ |
case 1: |
p16 = MakePtr(uint16_t*, img_base, offs); |
*p16+= (uint16_t)(delta>>16); |
break; |
case 2: |
p16 = MakePtr(uint16_t*, img_base, offs); |
*p16+= (uint16_t)delta; |
break; |
case 3: |
p32 = MakePtr(uint32_t*, img_base, offs); |
*p32+= delta; |
} |
entry++; |
} |
reloc = MakePtr(PIMAGE_BASE_RELOCATION, reloc,reloc->SizeOfBlock); |
}; |
// printf("unmap base %p offset %x %d page(s)\n", |
// img_base, |
// nt->OptionalHeader.DataDirectory[5].VirtualAddress, |
// (nt->OptionalHeader.DataDirectory[5].Size+4095)>>12); |
user_unmap(img_base,nt->OptionalHeader.DataDirectory[5].VirtualAddress, |
nt->OptionalHeader.DataDirectory[5].Size); |
}; |
return img_base; |
}; |
void* get_entry_point(void *raw) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
dos = (PIMAGE_DOS_HEADER)raw; |
nt = MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); |
return MakePtr(void*, raw, nt->OptionalHeader.AddressOfEntryPoint); |
}; |
void* load_libc() |
{ |
void *raw_img; |
size_t raw_size; |
void *img_base = NULL; |
ufile_t uf; |
uf = load_file("/kolibrios/lib/libc.dll"); |
raw_img = uf.data; |
raw_size = uf.size; |
if(raw_img == NULL) |
return NULL; |
// printf("libc.dll raw %p, size %d\n", raw_img, raw_size); |
if(validate_pe(raw_img, raw_size) != 0) |
{ |
// printf("invalide libc.dll\n"); |
img_base = create_image(raw_img); |
}; |
user_free(raw_img); |
return img_base; |
} |
/contrib/sdk/sources/newlib/pe/libc.asm |
---|
0,0 → 1,284 |
struc APP_HEADER_02 |
{ .banner dq ? |
.version dd ? ;+8 |
.start dd ? ;+12 |
.i_end dd ? ;+16 |
.mem_size dd ? ;+20 |
.stack_top dd ? ;+24 |
.cmdline dd ? ;+28 |
.path dd ? ;+32 |
} |
virtual at 0 |
app_hdr APP_HEADER_02 |
end virtual |
format MS COFF |
public EXPORTS |
section '.flat' code readable align 16 |
EXPORTS: |
dd szStart, START |
dd szVersion, 0x00010001 |
dd szExec, exec |
dd 0 |
check dd 0 |
szStart db 'START',0 |
szVersion db 'version',0 |
szExec db 'exec',0 |
START: |
xor eax, eax |
cmp [app_hdr.path], 0 |
je .ret |
not eax |
.ret: |
mov [check], eax |
ret 4 |
align 4 |
exec: |
cmp [check], 0 |
lea ebp, [esp+4] |
je .fail |
mov eax, [ebp+8] |
test eax, eax |
jz .fail |
mov ecx, [ebp] |
mov edx, [ebp+4] |
call validate_pe |
test eax, eax |
jz .fail |
mov eax, 68 |
mov ebx, [ebp] |
mov ecx, [ebx+60] |
mov ecx, [ecx+96+ebx] ; app stack size |
add ecx, 4095 |
and ecx, -4096 |
mov ebx, 12 |
int 0x40 |
test eax, eax |
jz .fail |
add ecx, eax |
mov [fs:4], eax ;stack base |
mov [fs:8], ecx ;stack top |
mov esp, ecx |
sub esp, 1024 |
mov eax, 9 |
mov ebx, esp |
mov ecx, -1 |
int 0x40 |
mov eax, [ebx+30] |
mov [fs:0], eax ; save pid |
add esp, 1024 |
mov ecx, my_libc |
call create_image |
test eax, eax |
jz .fail |
mov ebx, [eax+60] |
mov ebx, [ebx+40+eax] |
add ebx, eax |
push ebp |
push EXPORTS |
push eax |
call ebx |
ret |
.fail: |
ret 4 |
align 4 |
validate_pe: |
test ecx, ecx |
je .L2 |
cmp edx, 63 |
jbe .L2 |
cmp [ecx], word 23117 |
je .L10 |
.L2: |
xor eax, eax |
ret |
align 4 |
.L10: |
mov eax, [ecx+60] |
test eax, eax |
je .L2 |
add ecx, eax |
jb .L2 |
cmp [ecx], dword 17744 |
jne .L2 |
cmp [ecx+4], word 332 |
jne .L2 |
test [ecx+23], byte 32 |
jne .L2 |
cmp [ecx+24], word 267 |
jne .L2 |
mov eax, [ecx+56] |
cmp eax, 4095 |
ja .L3 |
cmp eax, [ecx+60] |
jne .L2 |
test eax, eax |
je .L2 |
.L5: |
lea edx, [eax-1] |
test edx, eax |
jne .L2 |
mov eax, [ecx+60] |
test eax, eax |
je .L2 |
lea edx, [eax-1] |
test edx, eax |
jne .L2 |
xor eax, eax |
cmp [ecx+6], word 96 |
setbe al |
ret |
.L3: |
cmp eax, [ecx+60] |
jae .L5 |
jmp .L2 |
align 4 |
create_image: |
push ebp |
push edi |
push esi |
push ebx |
sub esp, 20 |
mov [esp+16], ecx |
mov eax, [ecx+60] |
add eax, ecx |
mov [esp], eax |
mov ecx, [eax+80] |
mov ebx, 12 |
mov eax, 68 |
int 0x40 |
test eax, eax |
je .L16 |
mov edx, [esp] |
mov ecx, [edx+84] |
mov esi, [esp+16] |
mov edi, eax |
shr ecx, 2 |
rep movsd |
mov cx, [edx+6] |
test cx, cx |
je .L17 |
add edx, 248 |
movzx ecx, cx |
lea ebp, [ecx-1] |
xor bl, bl |
jmp .L19 |
align 4 |
.L31: |
add edx, 40 |
inc ebx |
.L19: |
mov ecx, [edx+16] |
test ecx, ecx |
je .L18 |
mov esi, [edx+20] |
test esi, esi |
je .L18 |
add esi, [esp+16] |
mov edi, [edx+12] |
add edi, eax |
shr ecx, 2 |
rep movsd |
.L18: |
cmp ebx, ebp |
jne .L31 |
.L17: |
mov edx, [esp] |
mov ecx, [edx+164] |
test ecx, ecx |
je .L16 |
mov ebp, eax |
sub ebp, [edx+52] |
mov ebx, [edx+160] |
add ebx, eax |
mov esi, [ebx+4] |
test esi, esi |
je .L16 |
mov edi, ebp |
shr edi, 16 |
mov [esp], di |
align 4 |
.L26: |
lea edi, [esi-8] |
shr edi, 1 |
je .L20 |
xor ecx, ecx |
jmp .L25 |
align 4 |
.L32: |
cmp si, 3 |
je .L24 |
dec si |
jne .L21 |
mov esi, [esp] |
add [eax+edx], si |
.L21: |
inc ecx |
cmp ecx, edi |
je .L20 |
.L25: |
mov si, [ebx+8+ecx*2] |
mov edx, esi |
and edx, 4095 |
add edx, [ebx] |
shr si, 12 |
cmp si, 2 |
jne .L32 |
add [eax+edx], bp |
inc ecx |
cmp ecx, edi |
jne .L25 |
.L20: |
add ebx, [ebx+4] |
mov esi, [ebx+4] |
test esi, esi |
jne .L26 |
.L16: |
add esp, 20 |
pop ebx |
pop esi |
pop edi |
pop ebp |
ret |
align 4 |
.L24: |
add [eax+edx], ebp |
jmp .L21 |
align 16 |
my_libc: |
file '../libc.dll' |
/contrib/sdk/sources/newlib/pe/list.h |
---|
0,0 → 1,707 |
#ifndef _LINUX_LIST_H |
#define _LINUX_LIST_H |
/* |
* Simple doubly linked list implementation. |
* |
* Some of the internal functions ("__xxx") are useful when |
* manipulating whole lists rather than single entries, as |
* sometimes we already know the next/prev entries and we can |
* generate better code by using them directly rather than |
* using the generic single-entry routines. |
*/ |
/** |
* container_of - cast a member of a structure out to the containing structure |
* @ptr: the pointer to the member. |
* @type: the type of the container struct this is embedded in. |
* @member: the name of the member within the struct. |
* |
*/ |
#define container_of(ptr, type, member) ({ \ |
const typeof( ((type *)0)->member ) *__mptr = (ptr); \ |
(type *)( (char *)__mptr - offsetof(type,member) );}) |
#define LIST_POISON1 ((struct list_head*)0xFFFF0100) |
#define LIST_POISON2 ((struct list_head*)0xFFFF0200) |
#define prefetch(x) __builtin_prefetch(x) |
struct list_head { |
struct list_head *next, *prev; |
}; |
#define LIST_HEAD_INIT(name) { &(name), &(name) } |
#define LIST_HEAD(name) \ |
struct list_head name = LIST_HEAD_INIT(name) |
static inline void INIT_LIST_HEAD(struct list_head *list) |
{ |
list->next = list; |
list->prev = list; |
} |
/* |
* Insert a new entry between two known consecutive entries. |
* |
* This is only for internal list manipulation where we know |
* the prev/next entries already! |
*/ |
#ifndef CONFIG_DEBUG_LIST |
static inline void __list_add(struct list_head *new, |
struct list_head *prev, |
struct list_head *next) |
{ |
next->prev = new; |
new->next = next; |
new->prev = prev; |
prev->next = new; |
} |
#else |
extern void __list_add(struct list_head *new, |
struct list_head *prev, |
struct list_head *next); |
#endif |
/** |
* list_add - add a new entry |
* @new: new entry to be added |
* @head: list head to add it after |
* |
* Insert a new entry after the specified head. |
* This is good for implementing stacks. |
*/ |
static inline void list_add(struct list_head *new, struct list_head *head) |
{ |
__list_add(new, head, head->next); |
} |
/** |
* list_add_tail - add a new entry |
* @new: new entry to be added |
* @head: list head to add it before |
* |
* Insert a new entry before the specified head. |
* This is useful for implementing queues. |
*/ |
static inline void list_add_tail(struct list_head *new, struct list_head *head) |
{ |
__list_add(new, head->prev, head); |
} |
/* |
* Delete a list entry by making the prev/next entries |
* point to each other. |
* |
* This is only for internal list manipulation where we know |
* the prev/next entries already! |
*/ |
static inline void __list_del(struct list_head * prev, struct list_head * next) |
{ |
next->prev = prev; |
prev->next = next; |
} |
/** |
* list_del - deletes entry from list. |
* @entry: the element to delete from the list. |
* Note: list_empty() on entry does not return true after this, the entry is |
* in an undefined state. |
*/ |
#ifndef CONFIG_DEBUG_LIST |
static inline void list_del(struct list_head *entry) |
{ |
__list_del(entry->prev, entry->next); |
entry->next = LIST_POISON1; |
entry->prev = LIST_POISON2; |
} |
#else |
extern void list_del(struct list_head *entry); |
#endif |
/** |
* list_replace - replace old entry by new one |
* @old : the element to be replaced |
* @new : the new element to insert |
* |
* If @old was empty, it will be overwritten. |
*/ |
static inline void list_replace(struct list_head *old, |
struct list_head *new) |
{ |
new->next = old->next; |
new->next->prev = new; |
new->prev = old->prev; |
new->prev->next = new; |
} |
static inline void list_replace_init(struct list_head *old, |
struct list_head *new) |
{ |
list_replace(old, new); |
INIT_LIST_HEAD(old); |
} |
/** |
* list_del_init - deletes entry from list and reinitialize it. |
* @entry: the element to delete from the list. |
*/ |
static inline void list_del_init(struct list_head *entry) |
{ |
__list_del(entry->prev, entry->next); |
INIT_LIST_HEAD(entry); |
} |
/** |
* list_move - delete from one list and add as another's head |
* @list: the entry to move |
* @head: the head that will precede our entry |
*/ |
static inline void list_move(struct list_head *list, struct list_head *head) |
{ |
__list_del(list->prev, list->next); |
list_add(list, head); |
} |
/** |
* list_move_tail - delete from one list and add as another's tail |
* @list: the entry to move |
* @head: the head that will follow our entry |
*/ |
static inline void list_move_tail(struct list_head *list, |
struct list_head *head) |
{ |
__list_del(list->prev, list->next); |
list_add_tail(list, head); |
} |
/** |
* list_is_last - tests whether @list is the last entry in list @head |
* @list: the entry to test |
* @head: the head of the list |
*/ |
static inline int list_is_last(const struct list_head *list, |
const struct list_head *head) |
{ |
return list->next == head; |
} |
/** |
* list_empty - tests whether a list is empty |
* @head: the list to test. |
*/ |
static inline int list_empty(const struct list_head *head) |
{ |
return head->next == head; |
} |
/** |
* list_empty_careful - tests whether a list is empty and not being modified |
* @head: the list to test |
* |
* Description: |
* tests whether a list is empty _and_ checks that no other CPU might be |
* in the process of modifying either member (next or prev) |
* |
* NOTE: using list_empty_careful() without synchronization |
* can only be safe if the only activity that can happen |
* to the list entry is list_del_init(). Eg. it cannot be used |
* if another CPU could re-list_add() it. |
*/ |
static inline int list_empty_careful(const struct list_head *head) |
{ |
struct list_head *next = head->next; |
return (next == head) && (next == head->prev); |
} |
/** |
* list_is_singular - tests whether a list has just one entry. |
* @head: the list to test. |
*/ |
static inline int list_is_singular(const struct list_head *head) |
{ |
return !list_empty(head) && (head->next == head->prev); |
} |
static inline void __list_cut_position(struct list_head *list, |
struct list_head *head, struct list_head *entry) |
{ |
struct list_head *new_first = entry->next; |
list->next = head->next; |
list->next->prev = list; |
list->prev = entry; |
entry->next = list; |
head->next = new_first; |
new_first->prev = head; |
} |
/** |
* list_cut_position - cut a list into two |
* @list: a new list to add all removed entries |
* @head: a list with entries |
* @entry: an entry within head, could be the head itself |
* and if so we won't cut the list |
* |
* This helper moves the initial part of @head, up to and |
* including @entry, from @head to @list. You should |
* pass on @entry an element you know is on @head. @list |
* should be an empty list or a list you do not care about |
* losing its data. |
* |
*/ |
static inline void list_cut_position(struct list_head *list, |
struct list_head *head, struct list_head *entry) |
{ |
if (list_empty(head)) |
return; |
if (list_is_singular(head) && |
(head->next != entry && head != entry)) |
return; |
if (entry == head) |
INIT_LIST_HEAD(list); |
else |
__list_cut_position(list, head, entry); |
} |
static inline void __list_splice(const struct list_head *list, |
struct list_head *prev, |
struct list_head *next) |
{ |
struct list_head *first = list->next; |
struct list_head *last = list->prev; |
first->prev = prev; |
prev->next = first; |
last->next = next; |
next->prev = last; |
} |
/** |
* list_splice - join two lists, this is designed for stacks |
* @list: the new list to add. |
* @head: the place to add it in the first list. |
*/ |
static inline void list_splice(const struct list_head *list, |
struct list_head *head) |
{ |
if (!list_empty(list)) |
__list_splice(list, head, head->next); |
} |
/** |
* list_splice_tail - join two lists, each list being a queue |
* @list: the new list to add. |
* @head: the place to add it in the first list. |
*/ |
static inline void list_splice_tail(struct list_head *list, |
struct list_head *head) |
{ |
if (!list_empty(list)) |
__list_splice(list, head->prev, head); |
} |
/** |
* list_splice_init - join two lists and reinitialise the emptied list. |
* @list: the new list to add. |
* @head: the place to add it in the first list. |
* |
* The list at @list is reinitialised |
*/ |
static inline void list_splice_init(struct list_head *list, |
struct list_head *head) |
{ |
if (!list_empty(list)) { |
__list_splice(list, head, head->next); |
INIT_LIST_HEAD(list); |
} |
} |
/** |
* list_splice_tail_init - join two lists and reinitialise the emptied list |
* @list: the new list to add. |
* @head: the place to add it in the first list. |
* |
* Each of the lists is a queue. |
* The list at @list is reinitialised |
*/ |
static inline void list_splice_tail_init(struct list_head *list, |
struct list_head *head) |
{ |
if (!list_empty(list)) { |
__list_splice(list, head->prev, head); |
INIT_LIST_HEAD(list); |
} |
} |
/** |
* list_entry - get the struct for this entry |
* @ptr: the &struct list_head pointer. |
* @type: the type of the struct this is embedded in. |
* @member: the name of the list_struct within the struct. |
*/ |
#define list_entry(ptr, type, member) \ |
container_of(ptr, type, member) |
/** |
* list_first_entry - get the first element from a list |
* @ptr: the list head to take the element from. |
* @type: the type of the struct this is embedded in. |
* @member: the name of the list_struct within the struct. |
* |
* Note, that list is expected to be not empty. |
*/ |
#define list_first_entry(ptr, type, member) \ |
list_entry((ptr)->next, type, member) |
/** |
* list_for_each - iterate over a list |
* @pos: the &struct list_head to use as a loop cursor. |
* @head: the head for your list. |
*/ |
#define list_for_each(pos, head) \ |
for (pos = (head)->next; prefetch(pos->next), pos != (head); \ |
pos = pos->next) |
/** |
* __list_for_each - iterate over a list |
* @pos: the &struct list_head to use as a loop cursor. |
* @head: the head for your list. |
* |
* This variant differs from list_for_each() in that it's the |
* simplest possible list iteration code, no prefetching is done. |
* Use this for code that knows the list to be very short (empty |
* or 1 entry) most of the time. |
*/ |
#define __list_for_each(pos, head) \ |
for (pos = (head)->next; pos != (head); pos = pos->next) |
/** |
* list_for_each_prev - iterate over a list backwards |
* @pos: the &struct list_head to use as a loop cursor. |
* @head: the head for your list. |
*/ |
#define list_for_each_prev(pos, head) \ |
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ |
pos = pos->prev) |
/** |
* list_for_each_safe - iterate over a list safe against removal of list entry |
* @pos: the &struct list_head to use as a loop cursor. |
* @n: another &struct list_head to use as temporary storage |
* @head: the head for your list. |
*/ |
#define list_for_each_safe(pos, n, head) \ |
for (pos = (head)->next, n = pos->next; pos != (head); \ |
pos = n, n = pos->next) |
/** |
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry |
* @pos: the &struct list_head to use as a loop cursor. |
* @n: another &struct list_head to use as temporary storage |
* @head: the head for your list. |
*/ |
#define list_for_each_prev_safe(pos, n, head) \ |
for (pos = (head)->prev, n = pos->prev; \ |
prefetch(pos->prev), pos != (head); \ |
pos = n, n = pos->prev) |
/** |
* list_for_each_entry - iterate over list of given type |
* @pos: the type * to use as a loop cursor. |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
*/ |
#define list_for_each_entry(pos, head, member) \ |
for (pos = list_entry((head)->next, typeof(*pos), member); \ |
prefetch(pos->member.next), &pos->member != (head); \ |
pos = list_entry(pos->member.next, typeof(*pos), member)) |
/** |
* list_for_each_entry_reverse - iterate backwards over list of given type. |
* @pos: the type * to use as a loop cursor. |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
*/ |
#define list_for_each_entry_reverse(pos, head, member) \ |
for (pos = list_entry((head)->prev, typeof(*pos), member); \ |
prefetch(pos->member.prev), &pos->member != (head); \ |
pos = list_entry(pos->member.prev, typeof(*pos), member)) |
/** |
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() |
* @pos: the type * to use as a start point |
* @head: the head of the list |
* @member: the name of the list_struct within the struct. |
* |
* Prepares a pos entry for use as a start point in list_for_each_entry_continue(). |
*/ |
#define list_prepare_entry(pos, head, member) \ |
((pos) ? : list_entry(head, typeof(*pos), member)) |
/** |
* list_for_each_entry_continue - continue iteration over list of given type |
* @pos: the type * to use as a loop cursor. |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
* |
* Continue to iterate over list of given type, continuing after |
* the current position. |
*/ |
#define list_for_each_entry_continue(pos, head, member) \ |
for (pos = list_entry(pos->member.next, typeof(*pos), member); \ |
prefetch(pos->member.next), &pos->member != (head); \ |
pos = list_entry(pos->member.next, typeof(*pos), member)) |
/** |
* list_for_each_entry_continue_reverse - iterate backwards from the given point |
* @pos: the type * to use as a loop cursor. |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
* |
* Start to iterate over list of given type backwards, continuing after |
* the current position. |
*/ |
#define list_for_each_entry_continue_reverse(pos, head, member) \ |
for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ |
prefetch(pos->member.prev), &pos->member != (head); \ |
pos = list_entry(pos->member.prev, typeof(*pos), member)) |
/** |
* list_for_each_entry_from - iterate over list of given type from the current point |
* @pos: the type * to use as a loop cursor. |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
* |
* Iterate over list of given type, continuing from current position. |
*/ |
#define list_for_each_entry_from(pos, head, member) \ |
for (; prefetch(pos->member.next), &pos->member != (head); \ |
pos = list_entry(pos->member.next, typeof(*pos), member)) |
/** |
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry |
* @pos: the type * to use as a loop cursor. |
* @n: another type * to use as temporary storage |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
*/ |
#define list_for_each_entry_safe(pos, n, head, member) \ |
for (pos = list_entry((head)->next, typeof(*pos), member), \ |
n = list_entry(pos->member.next, typeof(*pos), member); \ |
&pos->member != (head); \ |
pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
/** |
* list_for_each_entry_safe_continue |
* @pos: the type * to use as a loop cursor. |
* @n: another type * to use as temporary storage |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
* |
* Iterate over list of given type, continuing after current point, |
* safe against removal of list entry. |
*/ |
#define list_for_each_entry_safe_continue(pos, n, head, member) \ |
for (pos = list_entry(pos->member.next, typeof(*pos), member), \ |
n = list_entry(pos->member.next, typeof(*pos), member); \ |
&pos->member != (head); \ |
pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
/** |
* list_for_each_entry_safe_from |
* @pos: the type * to use as a loop cursor. |
* @n: another type * to use as temporary storage |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
* |
* Iterate over list of given type from current point, safe against |
* removal of list entry. |
*/ |
#define list_for_each_entry_safe_from(pos, n, head, member) \ |
for (n = list_entry(pos->member.next, typeof(*pos), member); \ |
&pos->member != (head); \ |
pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
/** |
* list_for_each_entry_safe_reverse |
* @pos: the type * to use as a loop cursor. |
* @n: another type * to use as temporary storage |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
* |
* Iterate backwards over list of given type, safe against removal |
* of list entry. |
*/ |
#define list_for_each_entry_safe_reverse(pos, n, head, member) \ |
for (pos = list_entry((head)->prev, typeof(*pos), member), \ |
n = list_entry(pos->member.prev, typeof(*pos), member); \ |
&pos->member != (head); \ |
pos = n, n = list_entry(n->member.prev, typeof(*n), member)) |
/* |
* Double linked lists with a single pointer list head. |
* Mostly useful for hash tables where the two pointer list head is |
* too wasteful. |
* You lose the ability to access the tail in O(1). |
*/ |
struct hlist_head { |
struct hlist_node *first; |
}; |
struct hlist_node { |
struct hlist_node *next, **pprev; |
}; |
#define HLIST_HEAD_INIT { .first = NULL } |
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } |
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) |
static inline void INIT_HLIST_NODE(struct hlist_node *h) |
{ |
h->next = NULL; |
h->pprev = NULL; |
} |
static inline int hlist_unhashed(const struct hlist_node *h) |
{ |
return !h->pprev; |
} |
static inline int hlist_empty(const struct hlist_head *h) |
{ |
return !h->first; |
} |
static inline void __hlist_del(struct hlist_node *n) |
{ |
struct hlist_node *next = n->next; |
struct hlist_node **pprev = n->pprev; |
*pprev = next; |
if (next) |
next->pprev = pprev; |
} |
static inline void hlist_del(struct hlist_node *n) |
{ |
__hlist_del(n); |
n->next = (struct hlist_node*)LIST_POISON1; |
n->pprev = (struct hlist_node**)LIST_POISON2; |
} |
static inline void hlist_del_init(struct hlist_node *n) |
{ |
if (!hlist_unhashed(n)) { |
__hlist_del(n); |
INIT_HLIST_NODE(n); |
} |
} |
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) |
{ |
struct hlist_node *first = h->first; |
n->next = first; |
if (first) |
first->pprev = &n->next; |
h->first = n; |
n->pprev = &h->first; |
} |
/* next must be != NULL */ |
static inline void hlist_add_before(struct hlist_node *n, |
struct hlist_node *next) |
{ |
n->pprev = next->pprev; |
n->next = next; |
next->pprev = &n->next; |
*(n->pprev) = n; |
} |
static inline void hlist_add_after(struct hlist_node *n, |
struct hlist_node *next) |
{ |
next->next = n->next; |
n->next = next; |
next->pprev = &n->next; |
if(next->next) |
next->next->pprev = &next->next; |
} |
/* |
* Move a list from one list head to another. Fixup the pprev |
* reference of the first entry if it exists. |
*/ |
static inline void hlist_move_list(struct hlist_head *old, |
struct hlist_head *new) |
{ |
new->first = old->first; |
if (new->first) |
new->first->pprev = &new->first; |
old->first = NULL; |
} |
#define hlist_entry(ptr, type, member) container_of(ptr,type,member) |
#define hlist_for_each(pos, head) \ |
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ |
pos = pos->next) |
#define hlist_for_each_safe(pos, n, head) \ |
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ |
pos = n) |
/** |
* hlist_for_each_entry - iterate over list of given type |
* @tpos: the type * to use as a loop cursor. |
* @pos: the &struct hlist_node to use as a loop cursor. |
* @head: the head for your list. |
* @member: the name of the hlist_node within the struct. |
*/ |
#define hlist_for_each_entry(tpos, pos, head, member) \ |
for (pos = (head)->first; \ |
pos && ({ prefetch(pos->next); 1;}) && \ |
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
pos = pos->next) |
/** |
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point |
* @tpos: the type * to use as a loop cursor. |
* @pos: the &struct hlist_node to use as a loop cursor. |
* @member: the name of the hlist_node within the struct. |
*/ |
#define hlist_for_each_entry_continue(tpos, pos, member) \ |
for (pos = (pos)->next; \ |
pos && ({ prefetch(pos->next); 1;}) && \ |
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
pos = pos->next) |
/** |
* hlist_for_each_entry_from - iterate over a hlist continuing from current point |
* @tpos: the type * to use as a loop cursor. |
* @pos: the &struct hlist_node to use as a loop cursor. |
* @member: the name of the hlist_node within the struct. |
*/ |
#define hlist_for_each_entry_from(tpos, pos, member) \ |
for (; pos && ({ prefetch(pos->next); 1;}) && \ |
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
pos = pos->next) |
/** |
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry |
* @tpos: the type * to use as a loop cursor. |
* @pos: the &struct hlist_node to use as a loop cursor. |
* @n: another &struct hlist_node to use as temporary storage |
* @head: the head for your list. |
* @member: the name of the hlist_node within the struct. |
*/ |
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ |
for (pos = (head)->first; \ |
pos && ({ n = pos->next; 1; }) && \ |
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
pos = n) |
#endif |
/contrib/sdk/sources/newlib/pe/loader.c |
---|
0,0 → 1,766 |
#include <stdint.h> |
#include <stdio.h> |
#include <string.h> |
#include <alloca.h> |
#include <malloc.h> |
#include <setjmp.h> |
#include <envz.h> |
#include <kos32sys.h> |
#include "list.h" |
#include "pe.h" |
#define unlikely(x) __builtin_expect(!!(x), 0) |
//#define DBG(format,...) printf(format,##__VA_ARGS__) |
#define DBG(format,...) |
void init_loader(void *libc_image); |
void* create_image(void *raw); |
int link_image(void *img_base, PIMAGE_IMPORT_DESCRIPTOR imp); |
extern char* __appenv; |
extern int __appenv_size; |
typedef struct tag_module module_t; |
struct app_hdr |
{ |
char banner[8]; |
int version; |
int start; |
int iend; |
int memsize; |
int stacktop; |
char *cmdline; |
char *path; |
int reserved; |
void *__idata_start; |
void *__idata_end; |
void (*main)(int argc, char **argv, char **envp); |
}; |
struct tag_module |
{ |
struct list_head list; |
char *img_name; |
char *img_path; |
uint32_t refcount; |
void *start; |
uint32_t end; |
void *entry; |
PIMAGE_NT_HEADERS32 img_hdr; |
PIMAGE_SECTION_HEADER img_sec; |
PIMAGE_EXPORT_DIRECTORY img_exp; |
}; |
typedef struct |
{ |
struct list_head list; |
char *path; |
int path_len; |
}dll_path_t; |
module_t* load_library(const char *name); |
LIST_HEAD(path_list); |
static module_t libc_dll; |
static char libc_name[] = "libc.dll"; |
static char libc_path[] = "/KolibriOS/lib/libc.dll"; |
static inline int IsPowerOf2(uint32_t val) |
{ |
if(val == 0) |
return 0; |
return (val & (val - 1)) == 0; |
} |
int validate_pe(void *raw, size_t raw_size, int is_exec) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
dos = (PIMAGE_DOS_HEADER)raw; |
if( !raw || raw_size < sizeof(IMAGE_DOS_HEADER) ) |
return 0; |
if( dos->e_magic != IMAGE_DOS_SIGNATURE || dos->e_lfanew <= 0) |
return 0; |
nt = MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); |
if( (uint32_t)nt < (uint32_t)raw) |
return 0; |
if(nt->Signature != IMAGE_NT_SIGNATURE) |
return 0; |
if(nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) |
return 0; |
if(is_exec && (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) |
return 0; |
if(nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) |
return 0; |
if( is_exec && nt->OptionalHeader.ImageBase != 0) |
return 0; |
if(nt->OptionalHeader.SectionAlignment < 4096) |
{ |
if(nt->OptionalHeader.FileAlignment != nt->OptionalHeader.SectionAlignment) |
return 0; |
} |
else if(nt->OptionalHeader.SectionAlignment < nt->OptionalHeader.FileAlignment) |
return 0; |
if(!IsPowerOf2(nt->OptionalHeader.SectionAlignment) || |
!IsPowerOf2(nt->OptionalHeader.FileAlignment)) |
return 0; |
if(nt->FileHeader.NumberOfSections > 96) |
return 0; |
return 1; |
} |
void init_loader(void *libc_image) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
PIMAGE_EXPORT_DIRECTORY exp; |
struct app_hdr *header = NULL; |
dll_path_t *path; |
int len; |
char *p; |
#if 0 |
if(__appenv_size) |
{ |
char *env; |
env = envz_get(__appenv, __appenv_size, "PATH"); |
if( env ) |
{ |
while( *env ) |
{ |
p = env; |
while(*p) |
{ |
if( *p == 0x0D) |
break; |
else if( *p == 0x0A) |
break; |
else if( *p == ':') |
break; |
p++; |
}; |
len = p-env; |
if(len) |
{ |
char *p1; |
p1 = (char*)malloc(len+1); |
memcpy(p1, env, len); |
p1[len]=0; |
path = (dll_path_t*)malloc(sizeof(dll_path_t)); |
INIT_LIST_HEAD(&path->list); |
path->path = p1; |
path->path_len = len; |
DBG("add libraries path %s\n", path->path); |
list_add_tail(&path->list, &path_list); |
}; |
if(*p == ':') |
{ |
env = p+1; |
continue; |
} |
else break; |
}; |
}; |
}; |
#endif |
len = strrchr(header->path, '/') - header->path+1; |
p = (char*)malloc(len+1); |
memcpy(p, header->path, len); |
p[len]=0; |
path = (dll_path_t*)malloc(sizeof(dll_path_t)); |
INIT_LIST_HEAD(&path->list); |
path->path = p; |
path->path_len = len; |
DBG("add libraries path %s\n", path->path); |
list_add_tail(&path->list, &path_list); |
path = (dll_path_t*)malloc(sizeof(dll_path_t)); |
INIT_LIST_HEAD(&path->list); |
path->path = "/kolibrios/lib/"; |
path->path_len = 15; /* FIXME */ |
DBG("add libraries path %s\n", path->path); |
list_add_tail(&path->list, &path_list); |
INIT_LIST_HEAD(&libc_dll.list); |
libc_dll.img_name = libc_name; |
libc_dll.img_path = libc_path; |
libc_dll.refcount = 1; |
dos = (PIMAGE_DOS_HEADER)libc_image; |
nt = MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); |
exp = MakePtr(PIMAGE_EXPORT_DIRECTORY, libc_image, |
nt->OptionalHeader.DataDirectory[0].VirtualAddress); |
libc_dll.start = libc_image; |
libc_dll.end = MakePtr(uint32_t,libc_image, nt->OptionalHeader.SizeOfImage); |
libc_dll.img_hdr = nt; |
libc_dll.img_sec = MakePtr(PIMAGE_SECTION_HEADER,nt, sizeof(IMAGE_NT_HEADERS32)); |
libc_dll.img_exp = MakePtr(PIMAGE_EXPORT_DIRECTORY,libc_image, |
nt->OptionalHeader.DataDirectory[0].VirtualAddress); |
}; |
static inline void sec_copy(void *dst, void *src, size_t len) |
{ |
__asm__ __volatile__ ( |
"shrl $2, %%ecx \n\t" |
"rep movsl" |
: |
:"c"(len),"S"(src),"D"(dst) |
:"cc"); |
__asm__ __volatile__ ( |
"" |
:::"ecx","esi","edi"); |
}; |
void* create_image(void *raw) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
PIMAGE_SECTION_HEADER img_sec; |
void *img_base; |
uint32_t sec_align; |
int i; |
dos = (PIMAGE_DOS_HEADER)raw; |
nt = MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); |
img_base = user_alloc(nt->OptionalHeader.SizeOfImage); |
if(unlikely(img_base == NULL)) |
return 0; |
sec_copy(img_base, raw, nt->OptionalHeader.SizeOfHeaders); |
img_sec = MakePtr(PIMAGE_SECTION_HEADER, nt, sizeof(IMAGE_NT_HEADERS32)); |
sec_align = nt->OptionalHeader.SectionAlignment; |
for(i=0; i< nt->FileHeader.NumberOfSections; i++) |
{ |
void *src_ptr; |
void *dest_ptr; |
size_t sec_size; |
if ( img_sec->SizeOfRawData && img_sec->PointerToRawData ) |
{ |
src_ptr = MakePtr(void*, raw, img_sec->PointerToRawData); |
dest_ptr = MakePtr(void*, img_base, img_sec->VirtualAddress); |
sec_copy(dest_ptr, src_ptr, img_sec->SizeOfRawData); |
}; |
img_sec++; |
}; |
if(nt->OptionalHeader.DataDirectory[5].Size) |
{ |
PIMAGE_BASE_RELOCATION reloc; |
uint32_t delta = (uint32_t)img_base - nt->OptionalHeader.ImageBase; |
reloc = MakePtr(PIMAGE_BASE_RELOCATION, img_base, |
nt->OptionalHeader.DataDirectory[5].VirtualAddress); |
while ( reloc->SizeOfBlock != 0 ) |
{ |
uint32_t cnt; |
uint16_t *entry; |
uint16_t reltype; |
uint32_t offs; |
cnt = (reloc->SizeOfBlock - sizeof(*reloc))/sizeof(uint16_t); |
entry = MakePtr( uint16_t*, reloc, sizeof(*reloc) ); |
for ( i=0; i < cnt; i++ ) |
{ |
uint16_t *p16; |
uint32_t *p32; |
reltype = (*entry & 0xF000) >> 12; |
offs = (*entry & 0x0FFF) + reloc->VirtualAddress; |
switch(reltype) |
{ |
case 1: |
p16 = MakePtr(uint16_t*, img_base, offs); |
*p16+= (uint16_t)(delta>>16); |
break; |
case 2: |
p16 = MakePtr(uint16_t*, img_base, offs); |
*p16+= (uint16_t)delta; |
break; |
case 3: |
p32 = MakePtr(uint32_t*, img_base, offs); |
*p32+= delta; |
} |
entry++; |
} |
reloc = MakePtr(PIMAGE_BASE_RELOCATION, reloc,reloc->SizeOfBlock); |
} |
}; |
return img_base; |
}; |
//static jmp_buf loader_env; |
//static loader_recursion; |
int link_image(void *img_base, PIMAGE_IMPORT_DESCRIPTOR imp) |
{ |
static jmp_buf loader_env; |
static recursion = -1; |
int warn = 0; |
recursion++; |
if( !recursion ) |
{ |
if( unlikely(setjmp(loader_env) != 0)) |
{ |
recursion = -1; |
return 0; |
}; |
}; |
while ( imp->Name ) |
{ |
PIMAGE_DOS_HEADER expdos; |
PIMAGE_NT_HEADERS32 expnt; |
PIMAGE_EXPORT_DIRECTORY exp; |
PIMAGE_THUNK_DATA32 thunk; |
void **iat; |
char *libname; |
uint32_t *exp_functions; |
uint16_t *exp_ordinals; |
char **exp_names; |
const module_t *api; |
libname=MakePtr(char*,imp->Name, img_base); |
DBG("import from %s\n",libname); |
api = load_library(libname); |
if(unlikely(api == NULL)) |
{ |
printf("library %s not found\n", libname); |
longjmp(loader_env, 1); |
} |
iat = MakePtr(void**,imp->FirstThunk, img_base); |
if(imp->OriginalFirstThunk !=0 ) |
{ |
thunk = MakePtr(PIMAGE_THUNK_DATA32,imp->OriginalFirstThunk, img_base); |
} |
else |
{ |
thunk = MakePtr(PIMAGE_THUNK_DATA32,imp->FirstThunk, img_base); |
}; |
exp = api->img_exp; |
exp_functions = MakePtr(uint32_t*,exp->AddressOfFunctions,api->start); |
exp_ordinals = MakePtr(uint16_t*, exp->AddressOfNameOrdinals,api->start); |
exp_names = MakePtr(char**, exp->AddressOfNames,api->start); |
while ( thunk->u1.AddressOfData != 0 ) |
{ |
PIMAGE_IMPORT_BY_NAME imp_name; |
if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) |
{ |
// ordinal = (*func_list) & 0x7fffffff; |
// *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal); |
// if ((*ImportAddressList) == NULL) |
// { |
// DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName); |
// RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName); |
// return STATUS_ENTRYPOINT_NOT_FOUND; |
// } |
} |
else |
{ |
char *export_name; |
uint16_t ordinal; |
void *function; |
uint32_t minn; |
uint32_t maxn; |
imp_name = MakePtr(PIMAGE_IMPORT_BY_NAME, |
thunk->u1.AddressOfData, img_base); |
*iat = NULL; |
DBG("import %s", imp_name->Name); |
if(imp_name->Hint < exp->NumberOfNames) |
{ |
export_name = MakePtr(char*,exp_names[imp_name->Hint], |
api->start); |
if(strcmp(imp_name->Name, export_name) == 0) |
{ |
ordinal = exp_ordinals[imp_name->Hint]; |
function = MakePtr(void*,exp_functions[ordinal], api->start); |
if((uint32_t)function >= (uint32_t)exp) |
{ |
printf("forward %s\n", function); |
warn=1; |
} |
else |
{ |
DBG(" \t\tat %x\n", function); |
*iat = function; |
}; |
thunk++; // Advance to next thunk |
iat++; |
continue; |
}; |
}; |
minn = 0; |
maxn = exp->NumberOfNames - 1; |
while (minn <= maxn) |
{ |
int mid; |
int res; |
mid = (minn + maxn) / 2; |
export_name = MakePtr(char*,exp_names[mid],api->start); |
res = strcmp(export_name, imp_name->Name); |
if (res == 0) |
{ |
ordinal = exp_ordinals[mid]; |
function = MakePtr(void*,exp_functions[ordinal], api->start); |
if((uint32_t)function >= (uint32_t)exp) |
{ |
printf("forward %s\n", function); |
warn=1; |
} |
else |
{ |
DBG(" \t\tat %x\n", function); |
*iat = function; |
}; |
break; |
} |
else if (minn == maxn) |
{ |
printf(" unresolved %s\n",imp_name->Name); |
warn=1; |
break; |
} |
else if (res > 0) |
{ |
maxn = mid - 1; |
} |
else |
{ |
minn = mid + 1; |
} |
}; |
}; |
thunk++; // Advance to next thunk |
iat++; |
} |
imp++; // advance to next IMAGE_IMPORT_DESCRIPTOR |
}; |
recursion--; |
if ( !warn ) |
return 1; |
else |
return 0; |
} |
int link_app() |
{ |
struct app_hdr *header = NULL; |
PIMAGE_IMPORT_DESCRIPTOR imp; |
imp = (PIMAGE_IMPORT_DESCRIPTOR)header->__idata_start; |
return link_image(NULL, imp); |
} |
void* get_entry_point(void *raw) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
dos = (PIMAGE_DOS_HEADER)raw; |
nt = MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); |
return MakePtr(void*, raw, nt->OptionalHeader.AddressOfEntryPoint); |
}; |
void *get_proc_address(module_t *module, char *proc_name) |
{ |
PIMAGE_DOS_HEADER expdos; |
PIMAGE_NT_HEADERS32 expnt; |
PIMAGE_EXPORT_DIRECTORY exp; |
uint32_t *exp_functions; |
uint16_t *exp_ordinals; |
char **exp_names; |
int minn, maxn; |
char *export_name; |
uint16_t ordinal; |
void *function=NULL; |
exp = module->img_exp; |
exp_functions = MakePtr(uint32_t*,exp->AddressOfFunctions,module->start); |
exp_ordinals = MakePtr(uint16_t*, exp->AddressOfNameOrdinals,module->start); |
exp_names = MakePtr(char**, exp->AddressOfNames,module->start); |
minn = 0; |
maxn = exp->NumberOfNames - 1; |
while (minn <= maxn) |
{ |
int mid; |
int res; |
mid = (minn + maxn) / 2; |
export_name = MakePtr(char*,exp_names[mid],module->start); |
res = strcmp(export_name, proc_name); |
if (res == 0) |
{ |
ordinal = exp_ordinals[mid]; |
function = MakePtr(void*,exp_functions[ordinal], module->start); |
if((uint32_t)function >= (uint32_t)exp) |
{ |
printf("forward %s\n", function); |
} |
else |
{ |
DBG(" \t\tat %x\n", function); |
}; |
break; |
} |
else if (minn == maxn) |
{ |
DBG(" unresolved %s\n",proc_name); |
break; |
} |
else if (res > 0) |
{ |
maxn = mid - 1; |
} |
else |
{ |
minn = mid + 1; |
} |
}; |
return function; |
}; |
static void *load_lib_internal(const char *path) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
PIMAGE_EXPORT_DIRECTORY exp; |
ufile_t uf; |
void *raw_img; |
size_t raw_size; |
void *img_base = NULL; |
uf = load_file(path); |
raw_img = uf.data; |
raw_size = uf.size; |
if(raw_img == NULL) |
return NULL; |
if( validate_pe(raw_img, raw_size, 0) == 0) |
{ |
printf("invalide module %s\n", path); |
user_free(raw_img); |
return NULL; |
}; |
img_base = create_image(raw_img); |
user_free(raw_img); |
if( unlikely(img_base == NULL) ) |
printf("cannot create image %s\n",path); |
return img_base; |
} |
module_t* load_library(const char *name) |
{ |
PIMAGE_DOS_HEADER dos; |
PIMAGE_NT_HEADERS32 nt; |
PIMAGE_EXPORT_DIRECTORY exp; |
module_t *module, *mod = &libc_dll; |
dll_path_t *dllpath; |
char *path; |
int len; |
char *libname, *tmp; |
void *img_base; |
/* check for already loaded libraries */ |
tmp = strrchr(name, '/'); |
libname = path = tmp != NULL ? tmp+1 : (char*)name; |
// printf("path %s\n", path); |
do |
{ |
if( !strncmp(path, mod->img_name, 16)) |
return mod; |
mod = (module_t*)mod->list.next; |
}while(mod != &libc_dll); |
if(name[0] == '/') |
{ |
path = (char*)name; |
img_base = load_lib_internal(path); |
} |
else |
{ |
len = strlen(libname); |
list_for_each_entry(dllpath, &path_list, list) |
{ |
path = alloca(len+dllpath->path_len+1); |
memcpy(path, dllpath->path, dllpath->path_len); |
memcpy(path+dllpath->path_len, libname, len); |
path[len+dllpath->path_len]=0; |
// printf("%s\n", path); |
img_base = load_lib_internal(path); |
if( unlikely(img_base == NULL) ) |
continue; |
}; |
} |
if( unlikely(img_base == NULL) ) |
{ |
printf("unable to load %s\n", name); |
return NULL; |
}; |
module = (module_t*)malloc(sizeof(module_t)); |
if(unlikely(module == NULL)) |
{ |
printf("%s epic fail: no enough memory\n",__FUNCTION__); |
goto err1; |
} |
INIT_LIST_HEAD(&module->list); |
module->img_name = strdup(libname); |
module->img_path = strdup(path); |
module->start = img_base; |
module->entry = get_entry_point(img_base); |
module->refcount = 1; |
dos = (PIMAGE_DOS_HEADER)img_base; |
nt = MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew); |
exp = MakePtr(PIMAGE_EXPORT_DIRECTORY, img_base, |
nt->OptionalHeader.DataDirectory[0].VirtualAddress); |
module->end = MakePtr(uint32_t,img_base, nt->OptionalHeader.SizeOfImage); |
module->img_hdr = nt; |
module->img_sec = MakePtr(PIMAGE_SECTION_HEADER,nt, sizeof(IMAGE_NT_HEADERS32)); |
module->img_exp = MakePtr(PIMAGE_EXPORT_DIRECTORY, img_base, |
nt->OptionalHeader.DataDirectory[0].VirtualAddress); |
list_add_tail(&module->list, &libc_dll.list); |
if(nt->OptionalHeader.DataDirectory[1].Size) |
{ |
PIMAGE_IMPORT_DESCRIPTOR imp; |
int (*dll_startup)(module_t *mod, uint32_t reason); |
imp = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, img_base, |
nt->OptionalHeader.DataDirectory[1].VirtualAddress); |
if(link_image(img_base, imp) == 0) |
goto err2; |
dll_startup = get_proc_address(module, "DllStartup"); |
if( dll_startup ) |
{ |
if( 0 == dll_startup(module, 1)) |
goto err2; |
} |
}; |
return module; |
err2: |
list_del(&module->list); |
free(module->img_name); |
free(module->img_path); |
free(module); |
err1: |
user_free(img_base); |
return NULL; |
}; |
/contrib/sdk/sources/newlib/pe/pe.h |
---|
0,0 → 1,188 |
typedef unsigned short WORD; |
typedef unsigned int DWORD; |
typedef unsigned int LONG; |
typedef unsigned char BYTE; |
#define IMAGE_DOS_SIGNATURE 0x5A4D |
#define IMAGE_NT_SIGNATURE 0x00004550 |
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b |
#pragma pack(push,2) |
typedef struct _IMAGE_DOS_HEADER |
{ |
WORD e_magic; |
WORD e_cblp; |
WORD e_cp; |
WORD e_crlc; |
WORD e_cparhdr; |
WORD e_minalloc; |
WORD e_maxalloc; |
WORD e_ss; |
WORD e_sp; |
WORD e_csum; |
WORD e_ip; |
WORD e_cs; |
WORD e_lfarlc; |
WORD e_ovno; |
WORD e_res[4]; |
WORD e_oemid; |
WORD e_oeminfo; |
WORD e_res2[10]; |
LONG e_lfanew; |
} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; |
#pragma pack(pop) |
#pragma pack(push,4) |
typedef struct _IMAGE_FILE_HEADER |
{ |
WORD Machine; |
WORD NumberOfSections; |
DWORD TimeDateStamp; |
DWORD PointerToSymbolTable; |
DWORD NumberOfSymbols; |
WORD SizeOfOptionalHeader; |
WORD Characteristics; |
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; |
#define IMAGE_FILE_DLL 0x2000 |
#define IMAGE_FILE_MACHINE_I386 0x014c /* Intel 386 or later processors |
and compatible processors */ |
typedef struct _IMAGE_DATA_DIRECTORY { |
DWORD VirtualAddress; |
DWORD Size; |
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; |
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 |
typedef struct _IMAGE_OPTIONAL_HEADER { |
WORD Magic; |
BYTE MajorLinkerVersion; |
BYTE MinorLinkerVersion; |
DWORD SizeOfCode; |
DWORD SizeOfInitializedData; |
DWORD SizeOfUninitializedData; |
DWORD AddressOfEntryPoint; |
DWORD BaseOfCode; |
DWORD BaseOfData; |
DWORD ImageBase; |
DWORD SectionAlignment; |
DWORD FileAlignment; |
WORD MajorOperatingSystemVersion; |
WORD MinorOperatingSystemVersion; |
WORD MajorImageVersion; |
WORD MinorImageVersion; |
WORD MajorSubsystemVersion; |
WORD MinorSubsystemVersion; |
DWORD Win32VersionValue; |
DWORD SizeOfImage; |
DWORD SizeOfHeaders; |
DWORD CheckSum; |
WORD Subsystem; |
WORD DllCharacteristics; |
DWORD SizeOfStackReserve; |
DWORD SizeOfStackCommit; |
DWORD SizeOfHeapReserve; |
DWORD SizeOfHeapCommit; |
DWORD LoaderFlags; |
DWORD NumberOfRvaAndSizes; |
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; |
} IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER; |
#pragma pack(pop) |
#pragma pack(push,4) |
typedef struct _IMAGE_NT_HEADERS |
{ |
DWORD Signature; |
IMAGE_FILE_HEADER FileHeader; |
IMAGE_OPTIONAL_HEADER OptionalHeader; |
} IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; |
#define IMAGE_SIZEOF_SHORT_NAME 8 |
typedef struct _IMAGE_SECTION_HEADER |
{ |
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; |
union |
{ |
DWORD PhysicalAddress; |
DWORD VirtualSize; |
} Misc; |
DWORD VirtualAddress; |
DWORD SizeOfRawData; |
DWORD PointerToRawData; |
DWORD PointerToRelocations; |
DWORD PointerToLinenumbers; |
WORD NumberOfRelocations; |
WORD NumberOfLinenumbers; |
DWORD Characteristics; |
} IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; |
#pragma pack(pop) |
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 |
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 |
#define IMAGE_SCN_MEM_SHARED 0x10000000 |
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 |
#define IMAGE_SCN_MEM_WRITE 0x80000000 |
#pragma pack(push,4) |
typedef struct _IMAGE_BASE_RELOCATION { |
DWORD VirtualAddress; |
DWORD SizeOfBlock; |
} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION; |
#pragma pack(pop) |
typedef struct _IMAGE_IMPORT_DESCRIPTOR |
{ |
union |
{ |
DWORD Characteristics; |
DWORD OriginalFirstThunk; |
}; |
DWORD TimeDateStamp; |
DWORD ForwarderChain; |
DWORD Name; |
DWORD FirstThunk; |
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR; |
typedef struct _IMAGE_THUNK_DATA32 |
{ |
union |
{ |
DWORD ForwarderString; |
DWORD Function; |
DWORD Ordinal; |
DWORD AddressOfData; |
} u1; |
} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32; |
typedef struct _IMAGE_IMPORT_BY_NAME |
{ |
WORD Hint; |
BYTE Name[1]; |
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; |
#define IMAGE_ORDINAL_FLAG 0x80000000 |
typedef struct _IMAGE_EXPORT_DIRECTORY { |
DWORD Characteristics; |
DWORD TimeDateStamp; |
WORD MajorVersion; |
WORD MinorVersion; |
DWORD Name; |
DWORD Base; |
DWORD NumberOfFunctions; |
DWORD NumberOfNames; |
DWORD AddressOfFunctions; |
DWORD AddressOfNames; |
DWORD AddressOfNameOrdinals; |
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; |
#define MakePtr( cast, ptr, addValue ) (cast)( (uint32_t)(ptr) + (uint32_t)(addValue) ) |