⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 peal.c

📁 wince下著名的视频播放器源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/********** * Copyright (c) 2004 Greg Parker.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **********/#include <PalmOS.h>#include <PalmOSGlue.h>#include <PceNativeCall.h>#include <stdint.h>#include <stddef.h>#include "peal.h"#include "elf.h"#define FTRID_STEP		64
typedef struct {    uint32_t vm_addr;    uint32_t block;    MemHandle resource;    Boolean is_ftr;
	Boolean is_lib;} SectionInfo;struct PealModule {
	size_t size;
	Boolean is_ftr;
	Boolean is_memsemaphore;
    const Elf32_Ehdr *ehdr;
	UInt32 prgId;
	UInt16 ftrId;
    int symcount;    const Elf32_Sym *syms;     // real address of .symtab section    const char *strings;       // real address of .strtab section    uintptr_t got;       // real address of .got section    uintptr_t rw_block;  // heap block containing rw_start (unaligned)    uintptr_t rw_start;  // real address of all r/w memory (aligned)    uintptr_t stub;      // PealArmStub()
    SectionInfo sinfo[1];// real addresses of each section
};// Must match struct PealArgs in arm/pealstub.ctypedef struct {    void *fn;    void *arg;    void *got;} PealArgs;static inline uint32_t swap32(uint32_t v){    return (            ((v & 0x000000ff) << 24) |            ((v & 0x0000ff00) << 8) |            ((v & 0x00ff0000) >> 8) |            ((v & 0xff000000) >> 24)            );}static inline uint16_t swap16(uint16_t v){    return (            ((v & 0x00ff) << 8) |            ((v & 0xff00) >> 8)            );}static inline void swap_ehdr(Elf32_Ehdr *ehdr){    ehdr->e_type      = swap16(ehdr->e_type);    ehdr->e_machine   = swap16(ehdr->e_machine);    ehdr->e_version   = swap32(ehdr->e_version);    ehdr->e_entry     = swap32(ehdr->e_entry);    ehdr->e_phoff     = swap32(ehdr->e_phoff);    ehdr->e_shoff     = swap32(ehdr->e_shoff);    ehdr->e_flags     = swap32(ehdr->e_flags);    ehdr->e_ehsize    = swap16(ehdr->e_ehsize);    ehdr->e_phentsize = swap16(ehdr->e_phentsize);    ehdr->e_phnum     = swap16(ehdr->e_phnum);    ehdr->e_shentsize = swap16(ehdr->e_shentsize);    ehdr->e_shnum     = swap16(ehdr->e_shnum);    ehdr->e_shstrndx  = swap16(ehdr->e_shstrndx);}static uint16_t peek16(uintptr_t block, uintptr_t dst){    block = block;     return swap16(*(uint16_t *)dst);}static uint32_t peek32(uintptr_t block, uintptr_t dst){    block = block;     return swap32(*(uint32_t *)dst);}static void poke16(PealModule *m,uintptr_t block, uintptr_t dst, uint16_t value){    ptrdiff_t offset = dst - block;    value = swap16(value);
	if (*(uint16_t *)dst != value)
	{
		if (!m->is_memsemaphore && errNone == DmWriteCheck((void *)block, offset, sizeof(value))) {			DmWrite((void *)block, offset, &value, sizeof(value));		} else {			*(uint16_t *)dst = value;		}
	}}static void poke32(PealModule *m,uintptr_t block, uintptr_t dst, uint32_t value){    ptrdiff_t offset = dst - block;    value = swap32(value);
	if (*(uint32_t *)dst != value)
	{
		if (!m->is_memsemaphore && errNone == DmWriteCheck((void *)block, offset, sizeof(value))) {			DmWrite((void *)block, offset, &value, sizeof(value));		} else {			*(uint32_t *)dst = value;		}
	}}static const Elf32_Shdr *section_for_index(const Elf32_Ehdr *ehdr, uint16_t index){    Elf32_Shdr *shdr;    if (index >= swap16(ehdr->e_shnum)) return NULL;    shdr = (Elf32_Shdr *)(((uint8_t *)ehdr)+swap32(ehdr->e_shoff));    return shdr+index;}static const char *section_name(const PealModule *m, const Elf32_Shdr *shdr){    // NOT m->strings!    const char *strings = (const char *)m->sinfo[swap16(m->ehdr->e_shstrndx)].vm_addr;    return strings + swap32(shdr->sh_name);}
static const char *symbol_name(const PealModule *m, const Elf32_Sym *sym)
{
    return m->strings + swap32(sym->st_name);
}

static const Elf32_Sym *symbol_lookup(const PealModule *m, const char *query, int hint)
{
	const Elf32_Sym *end;
	const Elf32_Sym *sym;
    int i;

    if (!m->syms  ||  !m->strings  ||  !query) return NULL;  // sorry

	if (hint >= m->symcount)
		hint = m->symcount-1;

	sym = m->syms+hint;
	i = StrCompareAscii(symbol_name(m, sym),query);
	if (i==0)
		return sym;

	// symtab has to be ordered by peal-postlink!
	if (i<0)
	{
		end = m->syms+m->symcount;
		for (++sym;sym<end;++sym)
			if (StrCompareAscii(symbol_name(m, sym),query)==0)
				return sym;
	}
	else
	{
		end = m->syms;
		for (--sym;sym>=end;--sym)
			if (StrCompareAscii(symbol_name(m, sym),query)==0)
				return sym;
	}
	return NULL;
}


// ELF file behaves like a .o, so st_value is an in-section offset#define thumb 1static uintptr_t symbol_address(const PealModule *m, const Elf32_Sym *sym, int interwork, const PealModule *common){
	uintptr_t address;
    int index = swap16(sym->st_shndx);

	if (m->sinfo[index].is_lib)
	{
		if (!common) return 0;
		sym = symbol_lookup(common, symbol_name(m,sym), swap32(sym->st_value) >> 2);
		if (!sym) return 0;
		m = common;
		index = swap16(sym->st_shndx);
	}

	address = (uintptr_t)(m->sinfo[index].vm_addr + swap32(sym->st_value));	if (interwork  &&  ELF32_ST_TYPE(sym->st_info) == STT_LOPROC) {		// symbol is a pointer to a Thumb function - use interworkable address		address++;	}	return address;
}/*    thunks from Thumb code:   BL:   thunk is Thumb, jumps to Thumb   BLX:  thunk is ARM, jumps to ARM      thunks from ARM code:   Bcc:  thunk is ARM, jumps to ARM   BLcc: thunk is ARM, jumps to ARM   BLX:  thunk is Thumb, jumps to Thumb*/// 1: thumb thunk// 0: arm thunk// -1: bad srcstatic int choose_thunk(uintptr_t src, Boolean srcIsThumb){    if (srcIsThumb) {        uint16_t insn1 = swap16(*(uint16_t *)src);        uint16_t insn2 = swap16(*(uint16_t *)(src+2));        uint16_t opcode1 = insn1 >> 11;        uint16_t opcode2 = insn2 >> 11;        if (opcode1 == 0x001e  &&  opcode2 == 0x001f) {            // BL: Thumb->Thumb branch, use Thumb thunk            return thumb;        } else if (opcode1 == 0x001e  &&  opcode2 == 0x001d) {            // BLX: Thumb->ARM branch, use ARM thunk            return 0;        } else {            // unknown instruction            return -1;        }    } else {        uint32_t insn = swap32(*(uint32_t *)src);        uint32_t cond = (insn & 0xf0000000) >> 28;        uint32_t opcode = (insn & 0x0e000000) >> 25;        if (opcode == 0x05) {            if (cond == 0x0f) {                // BLX: ARM->Thumb branch, use Thumb thunk                return thumb;            } else {                // Bcc, BLcc: ARM->ARM branch, use ARM thunk                return 0;            }        } else {            // unknown instruction            return -1;        }    }}/*    Thumb thunk   * 16 bytes total   * must be 4-byte aligned with leading NOP to handle ARM BLX   * data value is dst+1 so BX stays in Thumb mode   * for LDR, the PC is already 4 bytes ahead, and the immediate must      be 4-byte aligned. code (little-endian):   00 46C0  NOP    02 B401  PUSH r0   04 4801  LDR r0, [PC, #4]   06 4684  MOV r12, r0   08 BC01  POP r0   0a 4760  BX  r12 data:   0c 4-byte dst+1  (needs +1 so BX stays in Thumb mode)*//*   ARM thunk   * 8 bytes total   * for LDR, the PC is already 8 bytes ahead   * `LDR PC, ...` on ARMv5T will switch to Thumb mode if dest bit 0 is set,      but that should never happen here. code (big-endian):   00 E51FF004  LDR PC, [PC, #-4] data:   04 4-byte dst   */typedef struct {    uintptr_t thunk;    uintptr_t dst;} thunk_desc_t;// thunkList[0] is ARM, thunkList[1] is Thumbstatic thunk_desc_t *thunkList[2] = {NULL, NULL};static unsigned int thunksUsed[2] = {0, 0};static unsigned int thunksAllocated[2] = {0, 0};// arch 1 == Thumb, arch 0 == ARMstatic thunk_desc_t *find_thunk_desc(uintptr_t dst, int arch){    thunk_desc_t *desc;    unsigned int i;    // Search for existing thunk.    for (i = 0; i < thunksUsed[arch]; i++) {        desc = &thunkList[arch][i];        if (desc->dst == dst) return desc;    }    // No match. Make new thunk descriptor.    if (thunksUsed[arch] == thunksAllocated[arch]) {        thunk_desc_t *newList;        thunksAllocated[arch] = thunksAllocated[arch] * 2 + 8;        newList = MemPtrNew(thunksAllocated[arch] * sizeof(thunk_desc_t));        if (!newList) return NULL;        MemSet(newList, thunksAllocated[arch] * sizeof(thunk_desc_t), 0);        if (thunkList[arch]) {            MemMove(newList, thunkList[arch],                     thunksUsed[arch] * sizeof(thunk_desc_t));            MemPtrFree(thunkList[arch]);        }        thunkList[arch] = newList;    }    desc = &thunkList[arch][thunksUsed[arch]++];    desc->thunk = 0;    desc->dst = dst;    return desc;}static void free_thunk_descs(void){    if (thunkList[0]) MemPtrFree(thunkList[0]);    if (thunkList[1]) MemPtrFree(thunkList[1]);    thunkList[0] = thunkList[1] = NULL;    thunksUsed[0] = thunksUsed[1] = 0;    thunksAllocated[0] = thunksAllocated[1] = 0;}static Boolean insn_is_bx(uint16_t insn){    uint16_t opcode = insn >> 7;  // keep prefix+opcode+H1; discard H2+regs    return (opcode == 0x8e);  // 010001 11 0 x xxx xxx}static uintptr_t generate_thunk(PealModule *m,uintptr_t *thunks,                                 uintptr_t src_block, uintptr_t src,                                 uintptr_t dst, int srcIsThumb){    int thunkIsThumb;    thunk_desc_t *desc;    // Examine the instruction at *src to choose which thunk type we need.    thunkIsThumb = choose_thunk(src, srcIsThumb);    if (thunkIsThumb < 0) return 0;
    // Look for an existing thunk with the same dst and instruction set,     // and make a new one if necessary    desc = find_thunk_desc(dst, thunkIsThumb);    if (!desc) return 0; // out of memory    if (desc->thunk == 0) {        // New thunk.        if (thunkIsThumb) {            uint16_t target_insn = swap16(*(uint16_t *)dst);            desc->thunk = (*thunks -= 16);            if (insn_is_bx(target_insn)) {                // Branch target insn at dst is another bx (e.g. call_via_rX                 // glue). Simply copy that instruction into the stub.                // This is necessary for correctness - the Thumb thunk                 // interferes with call_via_ip - and also runs faster.                // fixme need to handle BLX too?                poke16(m,src_block, desc->thunk +  0, target_insn);            } else {                // Normal Thumb thunk.                poke16(m,src_block, desc->thunk +  0, 0x46C0); // NOP                poke16(m,src_block, desc->thunk +  2, 0xB401); // PUSH r0                poke16(m,src_block, desc->thunk +  4, 0x4801); // LDR  r0,[PC,#4]                poke16(m,src_block, desc->thunk +  6, 0x4684); // MOV  r12, r0                poke16(m,src_block, desc->thunk +  8, 0xBC01); // POP  r0                poke16(m,src_block, desc->thunk + 10, 0x4760); // BX   r12                poke32(m,src_block, desc->thunk + 12, dst | 1);            }        } else {            desc->thunk = (*thunks -= 8);            poke32(m,src_block, desc->thunk + 0, 0xE51FF004); // LDR PC, [PC,#-4]            poke32(m,src_block, desc->thunk + 4, dst);        }    }

    return desc->thunk;}static PealModule *allocate(const Elf32_Ehdr *ehdr){    size_t size = sizeof(SectionInfo) * (swap16(ehdr->e_shnum)-1) + sizeof(PealModule);    PealModule *m = MemPtrNew(size);    if (!m) return NULL;    // fixme sanity-check ehdr
    MemSet(m, size, 0);
	m->size = size;    m->ehdr = ehdr;    return m;}static void cleanup(PealModule *m){    free_thunk_descs();
    if (m) {
        unsigned int i, count = swap16(m->ehdr->e_shnum);
		for (i = 0; i < count; i++) {            if (m->sinfo[i].resource) {                MemHandleUnlock(m->sinfo[i].resource);                DmReleaseResource(m->sinfo[i].resource);            } else if (m->sinfo[i].is_ftr) {
				FtrPtrFree(m->prgId,m->ftrId+i);
            }        }        if (m->rw_block) MemPtrFree((void *)m->rw_block);
		if (m->is_ftr)
			FtrPtrFree(m->prgId,m->ftrId-1);
		else
			MemPtrFree(m);    }}static Boolean load(PealModule *m,const PealModule *common){    const Elf32_Shdr *shdr;    const Elf32_Sym *stub_sym;    uintptr_t rw_sh_addr;    uintptr_t rw_sh_end;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -