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

📄 peal.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
📖 第 1 页 / 共 2 页
字号:
    ptrdiff_t rw_slide;
    unsigned int i;
    uint32_t max_align = 1;

    // find extent of r/w memory
    rw_sh_addr   = 0xffffffff;
    rw_sh_end    = 0;
    for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) {
        uint32_t sh_flags = swap32(shdr->sh_flags);
        uint32_t sh_addr = swap32(shdr->sh_addr);
        uint32_t sh_size = swap32(shdr->sh_size);
        uint32_t sh_type = swap32(shdr->sh_type);
        uint32_t sh_addralign = swap32(shdr->sh_addralign);

        if ((sh_flags & SHF_ALLOC) && 
            (sh_type == SHT_PROGBITS || sh_type == SHT_NOBITS)) 
        {
            if ((sh_flags & SHF_WRITE)  &&  sh_addr < rw_sh_addr) {
                rw_sh_addr = sh_addr;
            }
            if ((sh_flags & SHF_WRITE)  &&  sh_addr + sh_size > rw_sh_end) {
                rw_sh_end = sh_addr + sh_size;
            }
            if (sh_addralign > max_align) {
                max_align = sh_addralign;
            }
        }
    }


    // allocate r/w memory
    if (rw_sh_addr == 0xffffffff  ||  rw_sh_addr == rw_sh_end) {
        m->rw_block = 0;
        m->rw_start = 0;
        rw_slide = 0;
    } else {
        // add leading pad to fix alignment in case first rw section
        // is less aligned than other rw sections.
        rw_sh_addr -= rw_sh_addr % max_align;

        // add leading pad to heap block in case max_align is 
        // more aligned than MemGluePtrNew's result.
        m->rw_block = (uintptr_t)MemGluePtrNew(rw_sh_end - rw_sh_addr + max_align);
        if (!m->rw_block) return false;
        m->rw_start = m->rw_block + (max_align - m->rw_block % max_align);
        if (m->rw_start % max_align) return false;

        rw_slide = m->rw_start - rw_sh_addr;
    }


    // populate r/w memory
    for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) {
        uint32_t sh_flags = swap32(shdr->sh_flags);
        uint32_t sh_addr = swap32(shdr->sh_addr);
        uint32_t sh_size = swap32(shdr->sh_size);
        uint32_t sh_type = swap32(shdr->sh_type);
        void *vm_addr = (void *)(sh_addr + rw_slide);

        if ((sh_flags & SHF_ALLOC)  &&  (sh_flags & SHF_WRITE)  &&  
            (sh_type == SHT_NOBITS  ||  sh_type == SHT_PROGBITS)) 
        {
            if (sh_type == SHT_NOBITS) {
                MemSet(vm_addr, sh_size, 0);  // .bss section
            } else {
                MemMove(vm_addr, (void *)m->sinfo[i].vm_addr, sh_size);
            }

            // use r/w location instead of r/o location from now on
            // If this section was in a large resource, block is a 
            // temporary heap buffer that is now freed.
            // fixme large temporary buffers suck
            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);
            }
            m->sinfo[i].block = m->rw_block;
            m->sinfo[i].vm_addr = (uintptr_t)vm_addr;
            m->sinfo[i].resource = 0;
            m->sinfo[i].is_ftr = false;
        }
    }


    // find symtab and string sections (both unique)
    m->syms = NULL;
    m->symcount = 0;
    m->strings = 0;
    for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) {
        if (swap32(shdr->sh_type) == SHT_SYMTAB) {
            m->syms = (Elf32_Sym *)m->sinfo[i].vm_addr;
            m->symcount = swap32(shdr->sh_size) / sizeof(Elf32_Sym);
        }
        if (swap32(shdr->sh_type) == SHT_STRTAB) {
            m->strings = (char *)m->sinfo[i].vm_addr;
        }
    }


    // find GOT using section named .got
    // This must be done AFTER the symtab, strtab, and slides are available
    // This must be done BEFORE relocations are performed
    m->got = 0;
    for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) {
        const char *name = section_name(m, shdr);
        if (0 == StrNCompareAscii(name, ".got", 5)) {
            m->got = m->sinfo[i].vm_addr;
        }
        if (0 == StrNCompareAscii(name, ".lib", 4)) {
            m->sinfo[i].is_lib = true;
        }
    }

	if (m->is_memsemaphore)
		MemSemaphoreReserve(1);

    // perform relocations
    // Don't use Thumb interworkable addresses for any relocation. 
    // All of these symbols should be section symbols, and any 
    // interwork mangling should have been done by peal-postlink.
    for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) {
        uint32_t sh_size = swap32(shdr->sh_size);
        uint32_t sh_type = swap32(shdr->sh_type);
        Elf32_Rela *rel, *relend;
        uint32_t dst_base;
        uintptr_t dst_block;
        size_t dst_size;
        uint32_t dst_index;
        uintptr_t dst_thunks;

        if (sh_type != SHT_RELA) continue;

        free_thunk_descs();

        rel = (Elf32_Rela *)m->sinfo[i].vm_addr;
        relend = rel + sh_size / sizeof(Elf32_Rela);
        
        dst_index = swap32(shdr->sh_info);
        dst_base = m->sinfo[dst_index].vm_addr;
        dst_block = m->sinfo[dst_index].block;
        dst_size = swap32(section_for_index(m->ehdr, dst_index)->sh_size);
        dst_thunks = dst_base + dst_size;  // assume postlinker aligned this

        for ( ; rel < relend; rel++) {
            uint32_t dst_offset;
            uint32_t sym_index;
            uintptr_t dst;
            uint32_t addend;
			uintptr_t symbol;

            dst_offset = swap32(rel->r_offset);
            sym_index = ELF32_R_SYM(swap32(rel->r_info));
            addend = swap32(rel->r_addend);
            symbol = symbol_address(m, m->syms + sym_index, 0, common);
			if (!symbol) goto fail;

            // *dst is ARM-swapped, and may be in storage memory. 
            // Use poke32() to change it.
            dst = dst_base + dst_offset;

            switch (ELF32_R_TYPE(swap32(rel->r_info))) {
            case R_ARM_PC24: {
                // *dst[0-23] = ((symbol + addend - dst) - 8) / 4
                // value must be SIGNED!
                int32_t value = symbol + addend - (uintptr_t)dst;
                if (value % 4) goto fail;
                value = (value - 8) / 4;

                if (value != ((value << 8) >> 8)) {
                    // Relocation no longer fits in 24 bits. Use a thunk.
                    uintptr_t thunk = 
                        generate_thunk(m, &dst_thunks, dst_block, dst, 
                                       symbol + addend, 0);
                    if (thunk == 0) goto fail;

                    // Re-aim value at the thunk.
                    value = thunk - (uintptr_t)dst;
                    if (value % 4) goto fail;
                    value = (value - 8) / 4;
                    if (value != ((value << 8) >> 8)) goto fail;
                }

                poke32(m,dst_block, dst, 
                       (value & 0x00ffffff) | 
                       (peek32(dst_block, dst) & 0xff000000));
                break;
            }
            case R_ARM_THM_PC22: {
                // *(dst+0)[0-10] = (((symbol + addend - dst) - 4) / 2)[11-21]
                // *(dst+2)[0-10] = (((symbol + addend - dst) - 4) / 2)[0-10]
                // value must be SIGNED!
                int32_t value = symbol + addend - (uintptr_t)dst;
                if (value % 2) goto fail;
                value = (value - 4) / 2;

                if (value != ((value << 10) >> 10)) {
                    // Relocation no longer fits in 22 bits. Use a thunk.
                    uintptr_t thunk = 
                        generate_thunk(m, &dst_thunks, dst_block, dst, 
                                       (symbol+addend) & 0xfffffffe, thumb);
                    if (thunk == 0) goto fail;

                    // Re-aim value at the thunk.
                    value = thunk - (uintptr_t)dst;
                    if (value % 2) goto fail;
                    value = (value - 4) / 2;
                    if (value != ((value << 10) >> 10)) goto fail;
                }

                poke16(m,dst_block, dst+0, 
                       ((value >> 11) & 0x07ff) | 
                       (peek16(dst_block, dst+0) & 0xf800));
                poke16(m,dst_block, dst+2, 
                       ((value >>  0) & 0x07ff) | 
                       (peek16(dst_block, dst+2) & 0xf800));
                break;
            }
            case R_ARM_ABS32:
                // *dst = symbol + addend
                poke32(m,dst_block, dst, 
                       symbol + addend);
                break;

            case R_ARM_REL32:
                // *dst = symbol + addend - dst 
                poke32(m,dst_block, dst, 
                       symbol + addend - (uintptr_t)dst);
                break;

            case R_ARM_GOTOFF:
                // *dst = symbol + addend - GOT
                if (!m->got) goto fail;
                poke32(m,dst_block, dst, 
                       symbol + addend - m->got);
                break;

            default:
                break;
            }
        }
    }

	if (m->is_memsemaphore)
		MemSemaphoreRelease(1);

    // find ARM-side stub function
    stub_sym = symbol_lookup(m, "PealArmStub", 0);
    if (stub_sym) {
        // Don't use a Thumb interworkable address for the stub, 
        // because PceNativeCall can't handle it.
        m->stub = symbol_address(m, stub_sym, 0, NULL);
    } else {
        m->stub = 0;
    }

    // fixme call initializers and C++ constructors here

    free_thunk_descs();

    return true;

fail:
	if (m->is_memsemaphore)
		MemSemaphoreRelease(1);
	return false;
}


PealModule *PealLoad(void *mem)
{
    int i;
    const Elf32_Shdr *shdr;
    const Elf32_Ehdr *ehdr;
    PealModule *m;

    ehdr = (const Elf32_Ehdr *)mem;

    m = allocate(ehdr);
    if (!m) return NULL;

    // find sections (contiguous version)
    for (i = 0; (shdr = section_for_index(ehdr, i)); i++) {
        m->sinfo[i].block = (uintptr_t)mem;
        m->sinfo[i].vm_addr = ((uintptr_t)mem) + swap32(shdr->sh_offset);
    }

    if (load(m,NULL)) {
        return m;
    } else {
        cleanup(m);
        return NULL; 
    }
}

Boolean isCodeSection(const Elf32_Shdr* shdr)
{
	uint32_t sh_flags = swap32(shdr->sh_flags);
	uint32_t sh_type = swap32(shdr->sh_type);

    if (sh_type == SHT_SYMTAB ||
		sh_type == SHT_STRTAB ||
		sh_type == SHT_RELA)
		return false;

    if ((sh_flags & SHF_ALLOC)  &&  (sh_flags & SHF_WRITE)  &&  
        (sh_type == SHT_NOBITS  ||  sh_type == SHT_PROGBITS))
		return false;

	return true;
}

PealModule *PealLoadFromResources(DmResType type, DmResID baseID, const PealModule *common, UInt32 prgId, UInt16 ftrId, Boolean memDup, Boolean onlyFtr, Boolean memSema)
{
    int i;
    int resID;
    PealModule *m;
    const Elf32_Shdr *shdr;
	Boolean rom;
    MemHandle rsrcH;
    const Elf32_Ehdr *ehdr;

    rsrcH = DmGet1Resource(type, baseID);
    if (!rsrcH) return NULL;
    ehdr = (Elf32_Ehdr *)MemHandleLock(rsrcH);

    m = allocate(ehdr);
    if (!m) {
        MemHandleUnlock(rsrcH);
        DmReleaseResource(rsrcH);
        return NULL;
    }

	m->is_memsemaphore = memSema;
	rom = DmWriteCheck((void*)ehdr,0,4) != errNone;

    // find sections (resource version)
    // resource baseID+0 is ehdr+shdrs
    // additional sections are in consecutive resources
    // sections bigger than 65400 bytes are split into multiple resources
    // section 0 (SHT_NULL) has no resource
    // Use section 0's sinfo to stash ehdr's resource
    resID = baseID+1;
	m->ftrId = ++ftrId;
	m->prgId = prgId;
    m->sinfo[0].block = (uintptr_t)ehdr;
    m->sinfo[0].vm_addr = 0;
    m->sinfo[0].resource = rsrcH;

	if (memDup)
	{
		// duplicate first section (header)
		size_t resSize;
		resSize = MemHandleSize(rsrcH);

		if (FtrPtrNew(prgId,ftrId,resSize,(void**)&m->sinfo[0].block)!=errNone) {
            cleanup(m);
            return NULL;
        }
		m->ehdr = (Elf32_Ehdr *)m->sinfo[0].block;
        m->sinfo[0].vm_addr = m->sinfo[0].block;
		m->sinfo[0].is_ftr = 1;
		m->sinfo[0].resource = 0;

		DmWrite((void*)m->ehdr,0,ehdr,resSize);
        MemHandleUnlock(rsrcH);
        DmReleaseResource(rsrcH);
	}

    for (i = 1; (shdr = section_for_index(m->ehdr, i)); i++) {
        uint32_t sh_type = swap32(shdr->sh_type);
        uint32_t sh_size = swap32(shdr->sh_size);
        size_t offset = 0;
        size_t left = sh_size;

        if (sh_size==0 || sh_type==SHT_NULL || sh_type==SHT_NOBITS) {
            // empty section or .bss section - no resource expected
            // m->sinfo[i] already zeroed
            continue;
        }

        do {
            size_t resSize;
            MemHandle rsrcH = DmGet1Resource(type, resID++);
            if (!rsrcH) {
                // no resource - bail
                cleanup(m);
                return NULL;
            }
            resSize = MemHandleSize(rsrcH);
            if (resSize > left) {
                // resource too big - bail
                DmReleaseResource(rsrcH);
                cleanup(m);
                return NULL;
            } else if (resSize == sh_size && !memDup && (!rom || !isCodeSection(shdr))) {
                // resource just right - keep it
                if (m->sinfo[i].block) {
                    // oops, already concatenating
                    DmReleaseResource(rsrcH);
                    cleanup(m);
                    return NULL;
                }
                m->sinfo[i].block = (uintptr_t)MemHandleLock(rsrcH);
                m->sinfo[i].vm_addr = m->sinfo[i].block;
                m->sinfo[i].resource = rsrcH;
            } else {
                // concatenate multiple resources
                if (!m->sinfo[i].block) {
					if (i>=FTRID_STEP-1 || FtrPtrNew(prgId,ftrId+i,sh_size,(void**)&m->sinfo[i].block)!=errNone) {
                        DmReleaseResource(rsrcH);
                        cleanup(m);
                        return NULL;
                    }
                    m->sinfo[i].vm_addr = m->sinfo[i].block;
                    m->sinfo[i].is_ftr = true;
                }
				DmWrite((void*)m->sinfo[i].block,offset,MemHandleLock(rsrcH), resSize);
                MemHandleUnlock(rsrcH);
                DmReleaseResource(rsrcH);
                offset += resSize;
            }
            left -= resSize;
        } while (left > 0);
    }

    if (load(m,common)) {

		PealModule *m2;
		if (onlyFtr && FtrPtrNew(prgId,ftrId-1,m->size,(void**)&m2)==errNone) {
			m->is_ftr = 1;
			DmWrite(m2,0,m,m->size);
			MemPtrFree(m);
			m = m2;
		}

        return m;
    } else {
        cleanup(m);  // this cleanup includes rsrcH
        return NULL; 
    }
}


void *PealLookupSymbol(const PealModule *m, char *query)
{
    const Elf32_Sym *sym = symbol_lookup(m, query, 0);
    // Do return Thumb interworkable addresses to client code
    return sym ? (void *)symbol_address(m, sym, thumb, NULL) : NULL;
}


uint32_t PealCall(PealModule *m, void *addr, void *arg)
{
    // args does not have to be aligned; ARM side handles misalignment and swap
    PealArgs args;
    args.fn = addr;
    args.arg = arg;
    args.got = (void *)m->got;

    return PceNativeCall((NativeFuncType *)m->stub, &args);
}


void PealUnload(PealModule *m)
{
    if (m) {
        // fixme call terminators and C++ destructors here
        cleanup(m);
    }
}


⌨️ 快捷键说明

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