wiiu-nanddumper-payload/ios_kernel/source/elf_patcher.c

111 lines
3.3 KiB
C

/***************************************************************************
* Copyright (C) 2016
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
***************************************************************************/
#include "types.h"
#include "elf_abi.h"
#include "utils.h"
static Elf32_Phdr * get_section(u32 data, u32 vaddr)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) data;
if ( !IS_ELF (*ehdr)
|| (ehdr->e_type != ET_EXEC)
|| (ehdr->e_machine != EM_ARM))
{
return 0;
}
Elf32_Phdr *phdr = 0;
u32 i;
for(i = 0; i < ehdr->e_phnum; i++)
{
phdr = (Elf32_Phdr *) (data + ehdr->e_phoff + ehdr->e_phentsize * i);
if((vaddr >= phdr[0].p_vaddr) && ((i == ehdr->e_phnum) || (vaddr < phdr[1].p_vaddr)))
{
break;
}
}
return phdr;
}
void section_write_bss(u32 ios_elf_start, u32 address, u32 size)
{
Elf32_Phdr *phdr = get_section(ios_elf_start, address);
if(!phdr)
return;
if((address - phdr->p_vaddr + size) > phdr->p_memsz)
{
phdr->p_memsz = (address - phdr->p_vaddr + size);
}
}
void section_write(u32 ios_elf_start, u32 address, const void *data, u32 size)
{
Elf32_Phdr *phdr = get_section(ios_elf_start, address);
if(!phdr)
return;
u32 *addr = (u32*)(ios_elf_start + address - phdr->p_vaddr + phdr->p_offset);
if((address - phdr->p_vaddr + size) > phdr->p_filesz)
{
u32 additionalSize = address - phdr->p_vaddr + size - phdr->p_filesz;
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ios_elf_start;
Elf32_Phdr * tmpPhdr;
u32 i;
for(i = (ehdr->e_phnum-1); i >= 0; i--)
{
tmpPhdr = (Elf32_Phdr *) (ios_elf_start + ehdr->e_phoff + ehdr->e_phentsize * i);
if(phdr->p_offset < tmpPhdr->p_offset)
{
reverse_memcpy((u8*)ios_elf_start + tmpPhdr->p_offset + additionalSize, (u8*)ios_elf_start + tmpPhdr->p_offset, tmpPhdr->p_filesz);
tmpPhdr->p_offset += additionalSize;
}
else {
break;
}
}
phdr->p_filesz += additionalSize;
if(phdr->p_memsz < phdr->p_filesz)
{
phdr->p_memsz = phdr->p_filesz;
}
}
// in most cases only a word is copied to an aligned address so do a short cut for performance
if(size == 4 && !((unsigned int)addr & 3) && !((unsigned int)data & 3))
{
*(u32*)addr = *(u32*)data;
}
else
{
kernel_memcpy(addr, data, size);
}
}