Compare commits

...

38 Commits

Author SHA1 Message Date
Maschell
ed5bdca3b9 Init GX2 to reduce screen corruption if no menu was shown 2024-07-06 15:34:43 +02:00
Maschell
4ad1400f9e Bump version 2024-07-06 10:52:59 +02:00
Maschell
fd803278f2 Update Dockerfile 2024-07-06 10:52:59 +02:00
Maschell
4d9e4f73c9 Limit the number of VPADRead attempts to avoid potential softlocks 2024-07-06 10:52:59 +02:00
Maschell
be78693cb7 Close the quick start menu on the gamepad if not autobooting into an environment 2024-07-06 10:52:59 +02:00
Maschell
f81ecf0178 Avoid screen corruption after displaying the environment selection screen 2024-07-06 10:52:59 +02:00
Maschell
95d0ce1385 Make rpx loading more robust and respect section alignment 2024-05-08 17:57:43 +02:00
dependabot[bot]
d9c743febd Bump wiiu-env/devkitppc from 20240423 to 20240505
Bumps wiiu-env/devkitppc from 20240423 to 20240505.

---
updated-dependencies:
- dependency-name: wiiu-env/devkitppc
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 10:20:31 +02:00
Maschell
95014a2123 Remove debug logs 2024-04-26 10:39:56 +02:00
Maschell
bdf9e079c8 Bump softprops/action-gh-release from 1 to 2 2024-04-26 10:39:56 +02:00
Maschell
7332dcaa1d Bump version to 0.3.0 2024-04-24 17:57:00 +02:00
dependabot[bot]
44d07c0e78 Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-24 17:57:00 +02:00
Maschell
e1d48361b6 Update Dockerfile to use latest devkitPPC and wut version 2024-04-24 17:57:00 +02:00
Maschell
5536bc79ee Fix compiling with debug flag 2024-04-24 17:57:00 +02:00
Maschell
b5f62f552d Make sure to init moduleInfoPtr 2024-04-24 17:57:00 +02:00
Maschell
35b8c0eeb7 Allow Aroma to init early 2024-04-24 17:57:00 +02:00
Maschell
2054d97e62 Avoid spamming the logs 2024-04-24 17:57:00 +02:00
Maschell
bd8992bc11 Update .gitignore to ignore .zip files 2024-04-24 17:57:00 +02:00
Maschell
e4d2dfa5aa Create dependabot.yml 2023-07-23 10:31:39 +02:00
Maschell
83cf3060c8 Bump version 2023-07-20 10:31:19 +02:00
Maschell
f60e8a340d Make input reading more reliable 2023-07-20 10:31:19 +02:00
Maschell
10337d5fba Display current version of EnvironmentLoader in the menu 2023-07-20 10:31:19 +02:00
Maschell
7dbd371d5a Update Dockerfile 2023-07-20 09:06:41 +02:00
Maschell
a6f7df7764 Allow using +/- to set the default environment 2023-06-16 17:43:57 +02:00
Maschell
5e4f93ddfa Add EnvironmentLoader to every OSFatal 2023-06-16 17:27:39 +02:00
Maschell
5da6afb310 Improve RPL loading when running the environment setup files 2023-06-16 17:27:39 +02:00
Maschell
0c0d73ffa3 Update the Dockerfile 2023-06-16 17:27:39 +02:00
Maschell
b3a7150c5d Implement support for pairing controller and GamePads 2023-06-16 17:27:39 +02:00
Maschell
f57dc4c163 Update Dockerfile and fix compiling with latest wut 2023-04-17 13:56:56 +02:00
Maschell
8fdf6d88c4 Change docker registry to ghcr.io 2023-03-17 18:56:29 +01:00
Maschell
9a065a8697 Update the CI to use a non-deprecated release action 2023-01-11 13:42:58 +01:00
Maschell
41af813a2d Use libschrift instead of freetype 2023-01-05 16:51:35 +01:00
Maschell
3c5cdbba5e Update Dockerfile 2023-01-05 16:41:11 +01:00
Maschell
ddcee53177 Update ELFIO to reduce binary size 2023-01-05 16:41:11 +01:00
Maschell
d24e6233d6 Add -Wextra flag to makefile 2023-01-05 16:41:11 +01:00
Maschell
25de833405 Improve commit messages for nightlies 2023-01-05 16:41:11 +01:00
Maschell
5f690a0824 Update CI to use actions/checkout@v3 2023-01-05 16:41:11 +01:00
Maschell
27d969e370 Update Makefile to be compatible with CLion 2023-01-05 16:41:11 +01:00
43 changed files with 7293 additions and 3356 deletions

10
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

@ -9,15 +9,22 @@ jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source --exclude ./source/elfio
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: create version.h
run: |
git_hash=$(git rev-parse --short "$GITHUB_SHA")
cat <<EOF > ./source/version.h
#pragma once
#define ENVIRONMENT_LOADER_VERSION_EXTRA " (nightly-$git_hash)"
EOF
- name: build binary
run: |
docker build . -t builder
@ -42,25 +49,12 @@ jobs:
- name: zip artifact
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip wiiu
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: "softprops/action-gh-release@v2"
with:
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
release_name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
draft: false
prerelease: true
body: |
Not a stable release:
${{ github.event.head_commit.message }}
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
asset_name: ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
asset_content_type: application/zip
generate_release_notes: true
name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
files: |
./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip

View File

@ -6,15 +6,15 @@ jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source --exclude ./source/elfio
check-build-with-logging:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: build binary with logging
run: |
docker build . -t builder
@ -25,7 +25,14 @@ jobs:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: create version.h
run: |
git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")
cat <<EOF > ./source/version.h
#pragma once
#define ENVIRONMENT_LOADER_VERSION_EXTRA " (nightly-$git_hash)"
EOF
- name: build binary
run: |
docker build . -t builder

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ cmake-build-debug/
*.txt
build1/
cmake-build-default/
*.zip

View File

@ -1,3 +1,3 @@
FROM wiiuenv/devkitppc:20220806
FROM ghcr.io/wiiu-env/devkitppc:20240704
WORKDIR project

View File

@ -31,7 +31,7 @@ INCLUDES := source
#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -g -Wall -O2 -ffunction-sections \
CFLAGS := -g -Wall -Wextra -O2 -ffunction-sections \
$(MACHDEP)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
@ -51,7 +51,7 @@ endif
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
LIBS := -lfreetype -lpng -lbz2 -lwut -lz
LIBS := -lwut -lz
#-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level
@ -100,7 +100,7 @@ export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD) -I$(DEVKITPRO)/portlibs/ppc/include/freetype2
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
@ -110,7 +110,7 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#-------------------------------------------------------------------------------

View File

@ -55,7 +55,7 @@ docker run -it --rm -v ${PWD}:/project environmentloader-builder make clean
## Format the code via docker
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source -i`
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source --exclude ./source/elfio -i`
## Credits
- maschell

View File

@ -3,32 +3,39 @@
#include <coreinit/cache.h>
#include <coreinit/debug.h>
#include <coreinit/dynload.h>
#include <coreinit/memdefaultheap.h>
#include "ElfUtils.h"
#include "elfio/elfio.hpp"
bool ElfUtils::doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length) {
bool ElfUtils::doRelocation(const std::vector<RelocationData> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, std::map<std::string, OSDynLoad_Module> &usedRPls) {
for (auto const &curReloc : relocData) {
std::string functionName = curReloc->getName();
std::string rplName = curReloc->getImportRPLInformation()->getRPLName();
int32_t isData = curReloc->getImportRPLInformation()->isData();
std::string functionName = curReloc.getName();
std::string rplName = curReloc.getImportRPLInformation()->getRPLName();
int32_t isData = curReloc.getImportRPLInformation()->isData();
OSDynLoad_Module rplHandle = nullptr;
auto err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
if (err != OS_DYNLOAD_OK || rplHandle == nullptr) {
// only acquire if not already loaded.
OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
if (!usedRPls.contains(rplName)) {
//DEBUG_FUNCTION_LINE_VERBOSE("Acquire %s", rplName.c_str());
// Always acquire to increase refcount and make sure it won't get unloaded while we're using it.
OSDynLoad_Error err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
if (err != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to acquire %s", rplName.c_str());
return false;
}
// Keep track RPLs we are using.
// They will be released on exit (See: AromaBaseModule)
usedRPls[rplName] = rplHandle;
} else {
//DEBUG_FUNCTION_LINE_VERBOSE("Use from usedRPLs cache! %s", rplName.c_str());
}
rplHandle = usedRPls[rplName];
uint32_t functionAddress = 0;
OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress);
if (functionAddress == 0) {
if ((OSDynLoad_FindExport(rplHandle, (OSDynLoad_ExportType) isData, functionName.c_str(), (void **) &functionAddress) != OS_DYNLOAD_OK) || functionAddress == 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to find export for %s %s %d", functionName.c_str(), rplName.c_str(), isData);
return false;
}
if (!ElfUtils::elfLinkOne(curReloc->getType(), curReloc->getOffset(), curReloc->getAddend(), (uint32_t) curReloc->getDestination(), functionAddress, tramp_data, tramp_length,
if (!ElfUtils::elfLinkOne(curReloc.getType(), curReloc.getOffset(), curReloc.getAddend(), (uint32_t) curReloc.getDestination(), functionAddress, tramp_data, tramp_length,
RELOC_TYPE_IMPORT)) {
DEBUG_FUNCTION_LINE_ERR("Relocation failed\n");
return false;
@ -152,7 +159,6 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
freeSlot->trampoline[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l
freeSlot->trampoline[2] = 0x7D6903A6; // mtctr r11
freeSlot->trampoline[3] = 0x4E800420; // bctr
DCFlushRange((void *) freeSlot->trampoline, sizeof(freeSlot->trampoline));
ICInvalidateRange((unsigned char *) freeSlot->trampoline, sizeof(freeSlot->trampoline));
if (reloc_type == RELOC_TYPE_FIXED) {

View File

@ -2,8 +2,10 @@
#include "common/relocation_defines.h"
#include "module/RelocationData.h"
#include <coreinit/dynload.h>
#include <cstdint>
#include <cstdio>
#include <map>
#include <memory>
#include <vector>
@ -49,6 +51,5 @@ public:
static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampolin_data, uint32_t trampolin_data_length,
RelocationType reloc_type);
static bool doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length);
static bool doRelocation(const std::vector<RelocationData> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, std::map<std::string, OSDynLoad_Module> &usedRPls);
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_ARRAY_HPP
#define ELFIO_ARRAY_HPP
#include <algorithm>
namespace ELFIO {
//------------------------------------------------------------------------------
template <class S, typename T> class array_section_accessor_template
{
public:
//------------------------------------------------------------------------------
explicit array_section_accessor_template( const elfio& elf_file,
S* section )
: elf_file( elf_file ), array_section( section )
{
}
//------------------------------------------------------------------------------
Elf_Xword get_entries_num() const
{
Elf_Xword entry_size = sizeof( T );
return array_section->get_size() / entry_size;
}
//------------------------------------------------------------------------------
bool get_entry( Elf_Xword index, Elf64_Addr& address ) const
{
if ( index >= get_entries_num() ) { // Is index valid
return false;
}
const endianess_convertor& convertor = elf_file.get_convertor();
const T temp = *reinterpret_cast<const T*>( array_section->get_data() +
index * sizeof( T ) );
address = convertor( temp );
return true;
}
//------------------------------------------------------------------------------
void add_entry( Elf64_Addr address )
{
const endianess_convertor& convertor = elf_file.get_convertor();
T temp = convertor( (T)address );
array_section->append_data( reinterpret_cast<char*>( &temp ),
sizeof( temp ) );
}
private:
//------------------------------------------------------------------------------
const elfio& elf_file;
S* array_section;
};
template <typename T = Elf32_Word>
using array_section_accessor = array_section_accessor_template<section, T>;
template <typename T = Elf32_Word>
using const_array_section_accessor =
array_section_accessor_template<const section, T>;
} // namespace ELFIO
#endif // ELFIO_ARRAY_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -24,60 +23,76 @@ THE SOFTWARE.
#ifndef ELFIO_DYNAMIC_HPP
#define ELFIO_DYNAMIC_HPP
#include <algorithm>
namespace ELFIO {
//------------------------------------------------------------------------------
template< class S >
class dynamic_section_accessor_template
template <class S> class dynamic_section_accessor_template
{
public:
//------------------------------------------------------------------------------
dynamic_section_accessor_template( const elfio& elf_file_, S* section_ ) :
elf_file( elf_file_ ),
dynamic_section( section_ )
//------------------------------------------------------------------------------
explicit dynamic_section_accessor_template( const elfio& elf_file,
S* section )
: elf_file( elf_file ), dynamic_section( section ), entries_num( 0 )
{
}
//------------------------------------------------------------------------------
Elf_Xword
get_entries_num() const
//------------------------------------------------------------------------------
Elf_Xword get_entries_num() const
{
Elf_Xword nRet = 0;
if ( 0 != dynamic_section->get_entry_size() ) {
nRet = dynamic_section->get_size() / dynamic_section->get_entry_size();
size_t needed_entry_size = -1;
if ( elf_file.get_class() == ELFCLASS32 ) {
needed_entry_size = sizeof( Elf32_Dyn );
}
else {
needed_entry_size = sizeof( Elf64_Dyn );
}
return nRet;
if ( ( 0 == entries_num ) &&
( 0 != dynamic_section->get_entry_size() &&
dynamic_section->get_entry_size() >= needed_entry_size ) ) {
entries_num =
dynamic_section->get_size() / dynamic_section->get_entry_size();
Elf_Xword i;
Elf_Xword tag = DT_NULL;
Elf_Xword value = 0;
std::string str;
for ( i = 0; i < entries_num; i++ ) {
get_entry( i, tag, value, str );
if ( tag == DT_NULL )
break;
}
entries_num = std::min<Elf_Xword>( entries_num, i + 1 );
}
return entries_num;
}
//------------------------------------------------------------------------------
bool
get_entry( Elf_Xword index,
Elf_Xword& tag,
Elf_Xword& value,
std::string& str ) const
//------------------------------------------------------------------------------
bool get_entry( Elf_Xword index,
Elf_Xword& tag,
Elf_Xword& value,
std::string& str ) const
{
if ( index >= get_entries_num() ) { // Is index valid
if ( index >= get_entries_num() ) { // Is index valid
return false;
}
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_get_entry_dyn< Elf32_Dyn >( index, tag, value );
generic_get_entry_dyn<Elf32_Dyn>( index, tag, value );
}
else {
generic_get_entry_dyn< Elf64_Dyn >( index, tag, value );
generic_get_entry_dyn<Elf64_Dyn>( index, tag, value );
}
// If the tag may have a string table reference, prepare the string
if ( tag == DT_NEEDED ||
tag == DT_SONAME ||
tag == DT_RPATH ||
// If the tag has a string table reference - prepare the string
if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH ||
tag == DT_RUNPATH ) {
string_section_accessor strsec =
elf_file.sections[ get_string_table_index() ];
const char* result = strsec.get_string( value );
if ( 0 == result ) {
string_section_accessor strsec(
elf_file.sections[get_string_table_index()] );
const char* result = strsec.get_string( (Elf_Word)value );
if ( nullptr == result ) {
str.clear();
return false;
}
@ -90,59 +105,55 @@ class dynamic_section_accessor_template
return true;
}
//------------------------------------------------------------------------------
void
add_entry( Elf_Xword tag,
Elf_Xword value )
//------------------------------------------------------------------------------
void add_entry( Elf_Xword tag, Elf_Xword value )
{
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_add_entry< Elf32_Dyn >( tag, value );
generic_add_entry_dyn<Elf32_Dyn>( tag, value );
}
else {
generic_add_entry< Elf64_Dyn >( tag, value );
generic_add_entry_dyn<Elf64_Dyn>( tag, value );
}
}
//------------------------------------------------------------------------------
void
add_entry( Elf_Xword tag,
const std::string& str )
//------------------------------------------------------------------------------
void add_entry( Elf_Xword tag, const std::string& str )
{
string_section_accessor strsec =
elf_file.sections[ get_string_table_index() ];
string_section_accessor strsec(
elf_file.sections[get_string_table_index()] );
Elf_Xword value = strsec.add_string( str );
add_entry( tag, value );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
Elf_Half
get_string_table_index() const
//------------------------------------------------------------------------------
Elf_Half get_string_table_index() const
{
return (Elf_Half)dynamic_section->get_link();
}
//------------------------------------------------------------------------------
template< class T >
void
generic_get_entry_dyn( Elf_Xword index,
Elf_Xword& tag,
Elf_Xword& value ) const
//------------------------------------------------------------------------------
template <class T>
void generic_get_entry_dyn( Elf_Xword index,
Elf_Xword& tag,
Elf_Xword& value ) const
{
const endianess_convertor& convertor = elf_file.get_convertor();
// Check unusual case when dynamic section has no data
if( dynamic_section->get_data() == 0 ||
( index + 1 ) * dynamic_section->get_entry_size() > dynamic_section->get_size() ) {
if ( dynamic_section->get_data() == nullptr ||
( index + 1 ) * dynamic_section->get_entry_size() >
dynamic_section->get_size() ||
dynamic_section->get_entry_size() < sizeof( T ) ) {
tag = DT_NULL;
value = 0;
return;
}
const T* pEntry = reinterpret_cast<const T*>(
dynamic_section->get_data() +
index * dynamic_section->get_entry_size() );
dynamic_section->get_data() +
index * dynamic_section->get_entry_size() );
tag = convertor( pEntry->d_tag );
switch ( tag ) {
case DT_NULL:
@ -188,10 +199,9 @@ class dynamic_section_accessor_template
}
}
//------------------------------------------------------------------------------
template< class T >
void
generic_add_entry( Elf_Xword tag, Elf_Xword value )
//------------------------------------------------------------------------------
template <class T>
void generic_add_entry_dyn( Elf_Xword tag, Elf_Xword value )
{
const endianess_convertor& convertor = elf_file.get_convertor();
@ -202,7 +212,8 @@ class dynamic_section_accessor_template
case DT_SYMBOLIC:
case DT_TEXTREL:
case DT_BIND_NOW:
value = 0;
entry.d_un.d_val = convertor( decltype( entry.d_un.d_val )( 0 ) );
break;
case DT_NEEDED:
case DT_PLTRELSZ:
case DT_RELASZ:
@ -219,7 +230,8 @@ class dynamic_section_accessor_template
case DT_RUNPATH:
case DT_FLAGS:
case DT_PREINIT_ARRAYSZ:
entry.d_un.d_val = convertor( value );
entry.d_un.d_val =
convertor( decltype( entry.d_un.d_val )( value ) );
break;
case DT_PLTGOT:
case DT_HASH:
@ -235,23 +247,27 @@ class dynamic_section_accessor_template
case DT_FINI_ARRAY:
case DT_PREINIT_ARRAY:
default:
entry.d_un.d_ptr = convertor( value );
entry.d_un.d_ptr =
convertor( decltype( entry.d_un.d_val )( value ) );
break;
}
entry.d_tag = convertor( tag );
entry.d_tag = convertor( decltype( entry.d_tag )( tag ) );
dynamic_section->append_data( reinterpret_cast<char*>( &entry ), sizeof( entry ) );
dynamic_section->append_data( reinterpret_cast<char*>( &entry ),
sizeof( entry ) );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
private:
const elfio& elf_file;
S* dynamic_section;
const elfio& elf_file;
S* dynamic_section;
mutable Elf_Xword entries_num;
};
using dynamic_section_accessor = dynamic_section_accessor_template<section>;
using const_dynamic_section_accessor = dynamic_section_accessor_template<const section>;
using const_dynamic_section_accessor =
dynamic_section_accessor_template<const section>;
} // namespace ELFIO

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -24,62 +23,61 @@ THE SOFTWARE.
#ifndef ELF_HEADER_HPP
#define ELF_HEADER_HPP
#include <iostream>
#include <cstring>
namespace ELFIO {
class elf_header
{
public:
virtual ~elf_header() {};
virtual bool load( std::istream& stream ) = 0;
virtual bool save( std::ostream& stream ) const = 0;
virtual ~elf_header() = default;
virtual bool load( const char * pBuffer, size_t pBufferSize ) = 0;
// ELF header functions
ELFIO_GET_ACCESS_DECL( unsigned char, class );
ELFIO_GET_ACCESS_DECL( unsigned char, elf_version );
ELFIO_GET_ACCESS_DECL( unsigned char, encoding );
ELFIO_GET_ACCESS_DECL( Elf_Half, header_size );
ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size );
ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size );
ELFIO_GET_ACCESS_DECL( unsigned char, class );
ELFIO_GET_ACCESS_DECL( unsigned char, elf_version );
ELFIO_GET_ACCESS_DECL( unsigned char, encoding );
ELFIO_GET_ACCESS_DECL( Elf_Half, header_size );
ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size );
ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version );
ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi );
ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version );
ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi );
ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset );
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index );
};
template< class T > struct elf_header_impl_types;
template<> struct elf_header_impl_types<Elf32_Ehdr> {
typedef Elf32_Phdr Phdr_type;
typedef Elf32_Shdr Shdr_type;
template <class T> struct elf_header_impl_types;
template <> struct elf_header_impl_types<Elf32_Ehdr>
{
using Phdr_type = Elf32_Phdr;
using Shdr_type = Elf32_Shdr;
static const unsigned char file_class = ELFCLASS32;
};
template<> struct elf_header_impl_types<Elf64_Ehdr> {
typedef Elf64_Phdr Phdr_type;
typedef Elf64_Shdr Shdr_type;
template <> struct elf_header_impl_types<Elf64_Ehdr>
{
using Phdr_type = Elf64_Phdr;
using Shdr_type = Elf64_Shdr;
static const unsigned char file_class = ELFCLASS64;
};
template< class T > class elf_header_impl : public elf_header
template <class T> class elf_header_impl : public elf_header
{
public:
elf_header_impl( endianess_convertor* convertor_,
unsigned char encoding )
//------------------------------------------------------------------------------
elf_header_impl( endianess_convertor* convertor,
unsigned char encoding )
: convertor( convertor )
{
convertor = convertor_;
std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ), '\0' );
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
@ -87,58 +85,56 @@ template< class T > class elf_header_impl : public elf_header
header.e_ident[EI_CLASS] = elf_header_impl_types<T>::file_class;
header.e_ident[EI_DATA] = encoding;
header.e_ident[EI_VERSION] = EV_CURRENT;
header.e_version = (*convertor)( (Elf_Word)EV_CURRENT );
header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT );
header.e_ehsize = ( sizeof( header ) );
header.e_ehsize = (*convertor)( header.e_ehsize );
header.e_shstrndx = (*convertor)( (Elf_Half)1 );
header.e_phentsize = sizeof( typename elf_header_impl_types<T>::Phdr_type );
header.e_shentsize = sizeof( typename elf_header_impl_types<T>::Shdr_type );
header.e_phentsize = (*convertor)( header.e_phentsize );
header.e_shentsize = (*convertor)( header.e_shentsize );
header.e_ehsize = ( *convertor )( header.e_ehsize );
header.e_shstrndx = ( *convertor )( (Elf_Half)1 );
header.e_phentsize =
sizeof( typename elf_header_impl_types<T>::Phdr_type );
header.e_shentsize =
sizeof( typename elf_header_impl_types<T>::Shdr_type );
header.e_phentsize = ( *convertor )( header.e_phentsize );
header.e_shentsize = ( *convertor )( header.e_shentsize );
}
bool
load( std::istream& stream )
//------------------------------------------------------------------------------
bool load( const char * pBuffer, size_t pBufferSize ) override
{
stream.seekg( 0 );
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
if(sizeof( header ) > pBufferSize) {
return false;
}
memcpy( reinterpret_cast<char*>( &header ), pBuffer, sizeof( header ));
return (stream.gcount() == sizeof( header ) );
}
bool
save( std::ostream& stream ) const
{
stream.seekp( 0 );
stream.write( reinterpret_cast<const char*>( &header ), sizeof( header ) );
return stream.good();
return true;
}
//------------------------------------------------------------------------------
// ELF header functions
ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] );
ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] );
ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] );
ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize );
ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize );
ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize );
ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] );
ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] );
ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] );
ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize );
ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize );
ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize );
ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version);
ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] );
ELFIO_GET_SET_ACCESS( unsigned char, abi_version, header.e_ident[EI_ABIVERSION] );
ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type );
ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine );
ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags );
ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx );
ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry );
ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum );
ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff );
ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum );
ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff );
ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version );
ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] );
ELFIO_GET_SET_ACCESS( unsigned char,
abi_version,
header.e_ident[EI_ABIVERSION] );
ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type );
ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine );
ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags );
ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx );
ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry );
ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum );
ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff );
ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum );
ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff );
private:
T header;
endianess_convertor* convertor;
T header = {};
endianess_convertor* convertor = nullptr;
};
} // namespace ELFIO

View File

@ -0,0 +1,124 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_MODINFO_HPP
#define ELFIO_MODINFO_HPP
#include <string>
#include <vector>
namespace ELFIO {
//------------------------------------------------------------------------------
template <class S> class modinfo_section_accessor_template
{
public:
//------------------------------------------------------------------------------
explicit modinfo_section_accessor_template( S* section )
: modinfo_section( section )
{
process_section();
}
//------------------------------------------------------------------------------
Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); }
//------------------------------------------------------------------------------
bool
get_attribute( Elf_Word no, std::string& field, std::string& value ) const
{
if ( no < content.size() ) {
field = content[no].first;
value = content[no].second;
return true;
}
return false;
}
//------------------------------------------------------------------------------
bool get_attribute( const std::string& field_name,
std::string& value ) const
{
for ( auto& i : content ) {
if ( field_name == i.first ) {
value = i.second;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
Elf_Word add_attribute( const std::string& field, const std::string& value )
{
Elf_Word current_position = 0;
if ( modinfo_section ) {
// Strings are addeded to the end of the current section data
current_position = (Elf_Word)modinfo_section->get_size();
std::string attribute = field + "=" + value;
modinfo_section->append_data( attribute + '\0' );
content.emplace_back( field, value );
}
return current_position;
}
//------------------------------------------------------------------------------
private:
void process_section()
{
const char* pdata = modinfo_section->get_data();
if ( pdata ) {
ELFIO::Elf_Xword i = 0;
while ( i < modinfo_section->get_size() ) {
while ( i < modinfo_section->get_size() && !pdata[i] )
i++;
if ( i < modinfo_section->get_size() ) {
std::string info = pdata + i;
size_t loc = info.find( '=' );
content.emplace_back( info.substr( 0, loc ),
info.substr( loc + 1 ) );
i += info.length();
}
}
}
}
//------------------------------------------------------------------------------
private:
S* modinfo_section;
std::vector<std::pair<std::string, std::string>> content;
};
using modinfo_section_accessor = modinfo_section_accessor_template<section>;
using const_modinfo_section_accessor =
modinfo_section_accessor_template<const section>;
} // namespace ELFIO
#endif // ELFIO_MODINFO_HPP

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -39,73 +38,75 @@ namespace ELFIO {
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
template< class S >
template <class S, Elf_Xword ( S::*F_get_size )() const>
class note_section_accessor_template
{
public:
//------------------------------------------------------------------------------
note_section_accessor_template( const elfio& elf_file_, S* section_ ) :
elf_file( elf_file_ ), note_section( section_ )
//------------------------------------------------------------------------------
explicit note_section_accessor_template( const elfio& elf_file, S* section )
: elf_file( elf_file ), notes( section )
{
process_section();
}
//------------------------------------------------------------------------------
Elf_Word
get_notes_num() const
//------------------------------------------------------------------------------
Elf_Word get_notes_num() const
{
return (Elf_Word)note_start_positions.size();
}
//------------------------------------------------------------------------------
bool
get_note( Elf_Word index,
Elf_Word& type,
std::string& name,
void*& desc,
Elf_Word& descSize ) const
//------------------------------------------------------------------------------
bool get_note( Elf_Word index,
Elf_Word& type,
std::string& name,
char*& desc,
Elf_Word& descSize ) const
{
if ( index >= note_section->get_size() ) {
if ( index >= ( notes->*F_get_size )() ) {
return false;
}
const char* pData = note_section->get_data() + note_start_positions[index];
int align = sizeof( Elf_Word );
const char* pData = notes->get_data() + note_start_positions[index];
int align = sizeof( Elf_Word );
const endianess_convertor& convertor = elf_file.get_convertor();
type = convertor( *(const Elf_Word*)( pData + 2*align ) );
type = convertor( *(const Elf_Word*)( pData + 2 * (size_t)align ) );
Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) );
descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) );
Elf_Xword max_name_size = note_section->get_size() - note_start_positions[index];
if ( namesz > max_name_size ||
namesz + descSize > max_name_size ) {
Elf_Xword max_name_size =
( notes->*F_get_size )() - note_start_positions[index];
if ( namesz < 1 || namesz > max_name_size ||
(Elf_Xword)namesz + descSize > max_name_size ) {
return false;
}
name.assign( pData + 3*align, namesz - 1);
name.assign( pData + 3 * (size_t)align, namesz - 1 );
if ( 0 == descSize ) {
desc = 0;
desc = nullptr;
}
else {
desc = const_cast<char*> ( pData + 3*align +
( ( namesz + align - 1 )/align )*align );
desc = const_cast<char*>( pData + 3 * (size_t)align +
( ( namesz + align - 1 ) / align ) *
(size_t)align );
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void add_note( Elf_Word type,
const std::string& name,
const void* desc,
const char* desc,
Elf_Word descSize )
{
const endianess_convertor& convertor = elf_file.get_convertor();
int align = sizeof( Elf_Word );
Elf_Word nameLen = (Elf_Word)name.size() + 1;
Elf_Word nameLenConv = convertor( nameLen );
int align = sizeof( Elf_Word );
Elf_Word nameLen = (Elf_Word)name.size() + 1;
Elf_Word nameLenConv = convertor( nameLen );
std::string buffer( reinterpret_cast<char*>( &nameLenConv ), align );
Elf_Word descSizeConv = convertor( descSize );
Elf_Word descSizeConv = convertor( descSize );
buffer.append( reinterpret_cast<char*>( &descSizeConv ), align );
type = convertor( type );
buffer.append( reinterpret_cast<char*>( &type ), align );
@ -113,58 +114,70 @@ class note_section_accessor_template
buffer.append( 1, '\x00' );
const char pad[] = { '\0', '\0', '\0', '\0' };
if ( nameLen % align != 0 ) {
buffer.append( pad, align - nameLen % align );
buffer.append( pad, (size_t)align - nameLen % align );
}
if ( desc != 0 && descSize != 0 ) {
buffer.append( reinterpret_cast<const char*>( desc ), descSize );
if ( desc != nullptr && descSize != 0 ) {
buffer.append( desc, descSize );
if ( descSize % align != 0 ) {
buffer.append( pad, align - descSize % align );
buffer.append( pad, (size_t)align - descSize % align );
}
}
note_start_positions.push_back( note_section->get_size() );
note_section->append_data( buffer );
note_start_positions.emplace_back( ( notes->*F_get_size )() );
notes->append_data( buffer );
}
private:
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void process_section()
{
const endianess_convertor& convertor = elf_file.get_convertor();
const char* data = note_section->get_data();
Elf_Xword size = note_section->get_size();
Elf_Xword current = 0;
const char* data = notes->get_data();
Elf_Xword size = ( notes->*F_get_size )();
Elf_Xword current = 0;
note_start_positions.clear();
// Is it empty?
if ( 0 == data || 0 == size ) {
if ( nullptr == data || 0 == size ) {
return;
}
int align = sizeof( Elf_Word );
while ( current + 3*align <= size ) {
note_start_positions.push_back( current );
Elf_Word namesz = convertor(
*(const Elf_Word*)( data + current ) );
Elf_Word align = sizeof( Elf_Word );
while ( current + (Elf_Xword)3 * align <= size ) {
Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) );
Elf_Word descsz = convertor(
*(const Elf_Word*)( data + current + sizeof( namesz ) ) );
*(const Elf_Word*)( data + current + sizeof( namesz ) ) );
Elf_Word advance =
(Elf_Xword)3 * sizeof( Elf_Word ) +
( ( namesz + align - 1 ) / align ) * (Elf_Xword)align +
( ( descsz + align - 1 ) / align ) * (Elf_Xword)align;
if ( namesz < size && descsz < size && current + advance <= size ) {
note_start_positions.emplace_back( current );
}
else {
break;
}
current += 3*sizeof( Elf_Word ) +
( ( namesz + align - 1 ) / align ) * align +
( ( descsz + align - 1 ) / align ) * align;
current += advance;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
private:
const elfio& elf_file;
S* note_section;
S* notes;
std::vector<Elf_Xword> note_start_positions;
};
using note_section_accessor = note_section_accessor_template<section>;
using const_note_section_accessor = note_section_accessor_template<const section>;
using note_section_accessor =
note_section_accessor_template<section, &section::get_size>;
using const_note_section_accessor =
note_section_accessor_template<const section, &section::get_size>;
using note_segment_accessor =
note_section_accessor_template<segment, &segment::get_file_size>;
using const_note_segment_accessor =
note_section_accessor_template<const segment, &segment::get_file_size>;
} // namespace ELFIO

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -26,8 +25,8 @@ THE SOFTWARE.
namespace ELFIO {
template<typename T> struct get_sym_and_type;
template<> struct get_sym_and_type< Elf32_Rel >
template <typename T> struct get_sym_and_type;
template <> struct get_sym_and_type<Elf32_Rel>
{
static int get_r_sym( Elf_Xword info )
{
@ -38,7 +37,7 @@ template<> struct get_sym_and_type< Elf32_Rel >
return ELF32_R_TYPE( (Elf_Word)info );
}
};
template<> struct get_sym_and_type< Elf32_Rela >
template <> struct get_sym_and_type<Elf32_Rela>
{
static int get_r_sym( Elf_Xword info )
{
@ -49,161 +48,219 @@ template<> struct get_sym_and_type< Elf32_Rela >
return ELF32_R_TYPE( (Elf_Word)info );
}
};
template<> struct get_sym_and_type< Elf64_Rel >
template <> struct get_sym_and_type<Elf64_Rel>
{
static int get_r_sym( Elf_Xword info )
{
return ELF64_R_SYM( info );
}
static int get_r_type( Elf_Xword info )
{
return ELF64_R_TYPE( info );
}
static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
};
template<> struct get_sym_and_type< Elf64_Rela >
template <> struct get_sym_and_type<Elf64_Rela>
{
static int get_r_sym( Elf_Xword info )
{
return ELF64_R_SYM( info );
}
static int get_r_type( Elf_Xword info )
{
return ELF64_R_TYPE( info );
}
static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
};
//------------------------------------------------------------------------------
template< class S >
class relocation_section_accessor_template
template <class S> class relocation_section_accessor_template
{
public:
//------------------------------------------------------------------------------
relocation_section_accessor_template( const elfio& elf_file_, S* section_ ) :
elf_file( elf_file_ ),
relocation_section( section_ )
//------------------------------------------------------------------------------
explicit relocation_section_accessor_template( const elfio& elf_file,
S* section )
: elf_file( elf_file ), relocation_section( section )
{
}
//------------------------------------------------------------------------------
Elf_Xword
get_entries_num() const
//------------------------------------------------------------------------------
Elf_Xword get_entries_num() const
{
Elf_Xword nRet = 0;
if ( 0 != relocation_section->get_entry_size() ) {
nRet = relocation_section->get_size() / relocation_section->get_entry_size();
nRet = relocation_section->get_size() /
relocation_section->get_entry_size();
}
return nRet;
}
//------------------------------------------------------------------------------
bool
get_entry( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
Elf_Word& type,
Elf_Sxword& addend ) const
//------------------------------------------------------------------------------
bool get_entry( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
unsigned& type,
Elf_Sxword& addend ) const
{
if ( index >= get_entries_num() ) { // Is index valid
if ( index >= get_entries_num() ) { // Is index valid
return false;
}
if ( elf_file.get_class() == ELFCLASS32 ) {
if ( SHT_REL == relocation_section->get_type() ) {
generic_get_entry_rel< Elf32_Rel >( index, offset, symbol,
type, addend );
generic_get_entry_rel<Elf32_Rel>( index, offset, symbol, type,
addend );
}
else if ( SHT_RELA == relocation_section->get_type() ) {
generic_get_entry_rela< Elf32_Rela >( index, offset, symbol,
type, addend );
generic_get_entry_rela<Elf32_Rela>( index, offset, symbol, type,
addend );
}
}
else {
if ( SHT_REL == relocation_section->get_type() ) {
generic_get_entry_rel< Elf64_Rel >( index, offset, symbol,
type, addend );
generic_get_entry_rel<Elf64_Rel>( index, offset, symbol, type,
addend );
}
else if ( SHT_RELA == relocation_section->get_type() ) {
generic_get_entry_rela< Elf64_Rela >( index, offset, symbol,
type, addend );
generic_get_entry_rela<Elf64_Rela>( index, offset, symbol, type,
addend );
}
}
return true;
}
//------------------------------------------------------------------------------
bool
get_entry( Elf_Xword index,
Elf64_Addr& offset,
Elf64_Addr& symbolValue,
std::string& symbolName,
Elf_Word& type,
Elf_Sxword& addend,
Elf_Half& section) const
//------------------------------------------------------------------------------
bool get_entry( Elf_Xword index,
Elf64_Addr& offset,
Elf64_Addr& symbolValue,
std::string& symbolName,
unsigned& type,
Elf_Sxword& addend,
Elf_Sxword& calcValue ) const
{
// Do regular job
Elf_Word symbol;
bool ret = get_entry( index, offset, symbol, type, addend );
Elf_Word symbol = 0;
bool ret = get_entry( index, offset, symbol, type, addend );
// Find the symbol
Elf_Xword size;
unsigned char bind;
unsigned char symbolType;
Elf_Half section;
unsigned char other;
symbol_section_accessor symbols( elf_file, elf_file.sections[get_symbol_table_index()] );
ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue,
size, bind, symbolType, section, other );
symbol_section_accessor symbols(
elf_file, elf_file.sections[get_symbol_table_index()] );
ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size,
bind, symbolType, section, other );
if ( ret ) { // Was it successful?
switch ( type ) {
case R_386_NONE: // none
calcValue = 0;
break;
case R_386_32: // S + A
calcValue = symbolValue + addend;
break;
case R_386_PC32: // S + A - P
calcValue = symbolValue + addend - offset;
break;
case R_386_GOT32: // G + A - P
calcValue = 0;
break;
case R_386_PLT32: // L + A - P
calcValue = 0;
break;
case R_386_COPY: // none
calcValue = 0;
break;
case R_386_GLOB_DAT: // S
case R_386_JMP_SLOT: // S
calcValue = symbolValue;
break;
case R_386_RELATIVE: // B + A
calcValue = addend;
break;
case R_386_GOTOFF: // S + A - GOT
calcValue = 0;
break;
case R_386_GOTPC: // GOT + A - P
calcValue = 0;
break;
default: // Not recognized symbol!
calcValue = 0;
break;
}
}
return ret;
}
//------------------------------------------------------------------------------
void
add_entry( Elf64_Addr offset, Elf_Xword info )
//------------------------------------------------------------------------------
bool set_entry( Elf_Xword index,
Elf64_Addr offset,
Elf_Word symbol,
unsigned type,
Elf_Sxword addend )
{
if ( index >= get_entries_num() ) { // Is index valid
return false;
}
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_add_entry< Elf32_Rel >( offset, info );
if ( SHT_REL == relocation_section->get_type() ) {
generic_set_entry_rel<Elf32_Rel>( index, offset, symbol, type,
addend );
}
else if ( SHT_RELA == relocation_section->get_type() ) {
generic_set_entry_rela<Elf32_Rela>( index, offset, symbol, type,
addend );
}
}
else {
generic_add_entry< Elf64_Rel >( offset, info );
if ( SHT_REL == relocation_section->get_type() ) {
generic_set_entry_rel<Elf64_Rel>( index, offset, symbol, type,
addend );
}
else if ( SHT_RELA == relocation_section->get_type() ) {
generic_set_entry_rela<Elf64_Rela>( index, offset, symbol, type,
addend );
}
}
return true;
}
//------------------------------------------------------------------------------
void add_entry( Elf64_Addr offset, Elf_Xword info )
{
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_add_entry<Elf32_Rel>( offset, info );
}
else {
generic_add_entry<Elf64_Rel>( offset, info );
}
}
//------------------------------------------------------------------------------
void
add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type )
//------------------------------------------------------------------------------
void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned type )
{
Elf_Xword info;
if ( elf_file.get_class() == ELFCLASS32 ) {
info = ELF32_R_INFO( (Elf_Xword)symbol, type );
}
else {
info = ELF64_R_INFO((Elf_Xword)symbol, type );
info = ELF64_R_INFO( (Elf_Xword)symbol, type );
}
add_entry( offset, info );
}
//------------------------------------------------------------------------------
void
add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
//------------------------------------------------------------------------------
void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
{
if ( elf_file.get_class() == ELFCLASS32 ) {
generic_add_entry< Elf32_Rela >( offset, info, addend );
generic_add_entry<Elf32_Rela>( offset, info, addend );
}
else {
generic_add_entry< Elf64_Rela >( offset, info, addend );
generic_add_entry<Elf64_Rela>( offset, info, addend );
}
}
//------------------------------------------------------------------------------
void
add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type,
Elf_Sxword addend )
//------------------------------------------------------------------------------
void add_entry( Elf64_Addr offset,
Elf_Word symbol,
unsigned type,
Elf_Sxword addend )
{
Elf_Xword info;
if ( elf_file.get_class() == ELFCLASS32 ) {
@ -216,48 +273,63 @@ class relocation_section_accessor_template
add_entry( offset, info, addend );
}
//------------------------------------------------------------------------------
void
add_entry( string_section_accessor str_writer,
const char* str,
symbol_section_accessor sym_writer,
Elf64_Addr value,
Elf_Word size,
unsigned char sym_info,
unsigned char other,
Elf_Half shndx,
Elf64_Addr offset,
unsigned char type )
//------------------------------------------------------------------------------
void add_entry( string_section_accessor str_writer,
const char* str,
symbol_section_accessor sym_writer,
Elf64_Addr value,
Elf_Word size,
unsigned char sym_info,
unsigned char other,
Elf_Half shndx,
Elf64_Addr offset,
unsigned type )
{
Elf_Word str_index = str_writer.add_string( str );
Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size,
sym_info, other, shndx );
sym_info, other, shndx );
add_entry( offset, sym_index, type );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void swap_symbols( Elf_Xword first, Elf_Xword second )
{
Elf64_Addr offset = 0;
Elf_Word symbol = 0;
unsigned rtype = 0;
Elf_Sxword addend = 0;
for ( Elf_Word i = 0; i < get_entries_num(); i++ ) {
get_entry( i, offset, symbol, rtype, addend );
if ( symbol == first ) {
set_entry( i, offset, (Elf_Word)second, rtype, addend );
}
if ( symbol == second ) {
set_entry( i, offset, (Elf_Word)first, rtype, addend );
}
}
}
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
Elf_Half
get_symbol_table_index() const
//------------------------------------------------------------------------------
Elf_Half get_symbol_table_index() const
{
return (Elf_Half)relocation_section->get_link();
}
//------------------------------------------------------------------------------
template< class T >
void
generic_get_entry_rel( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
Elf_Word& type,
Elf_Sxword& addend ) const
//------------------------------------------------------------------------------
template <class T>
void generic_get_entry_rel( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
unsigned& type,
Elf_Sxword& addend ) const
{
const endianess_convertor& convertor = elf_file.get_convertor();
const T* pEntry = reinterpret_cast<const T*>(
relocation_section->get_data() +
index * relocation_section->get_entry_size() );
relocation_section->get_data() +
index * relocation_section->get_entry_size() );
offset = convertor( pEntry->r_offset );
Elf_Xword tmp = convertor( pEntry->r_info );
symbol = get_sym_and_type<T>::get_r_sym( tmp );
@ -265,20 +337,19 @@ class relocation_section_accessor_template
addend = 0;
}
//------------------------------------------------------------------------------
template< class T >
void
generic_get_entry_rela( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
Elf_Word& type,
Elf_Sxword& addend ) const
//------------------------------------------------------------------------------
template <class T>
void generic_get_entry_rela( Elf_Xword index,
Elf64_Addr& offset,
Elf_Word& symbol,
unsigned& type,
Elf_Sxword& addend ) const
{
const endianess_convertor& convertor = elf_file.get_convertor();
const T* pEntry = reinterpret_cast<const T*>(
relocation_section->get_data() +
index * relocation_section->get_entry_size() );
relocation_section->get_data() +
index * relocation_section->get_entry_size() );
offset = convertor( pEntry->r_offset );
Elf_Xword tmp = convertor( pEntry->r_info );
symbol = get_sym_and_type<T>::get_r_sym( tmp );
@ -286,24 +357,76 @@ class relocation_section_accessor_template
addend = convertor( pEntry->r_addend );
}
//------------------------------------------------------------------------------
template< class T >
void
generic_add_entry( Elf64_Addr offset, Elf_Xword info )
//------------------------------------------------------------------------------
template <class T>
void generic_set_entry_rel( Elf_Xword index,
Elf64_Addr offset,
Elf_Word symbol,
unsigned type,
Elf_Sxword )
{
const endianess_convertor& convertor = elf_file.get_convertor();
T* pEntry = const_cast<T*>( reinterpret_cast<const T*>(
relocation_section->get_data() +
index * relocation_section->get_entry_size() ) );
if ( elf_file.get_class() == ELFCLASS32 ) {
pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type );
}
else {
pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type );
}
pEntry->r_offset = decltype( pEntry->r_offset )( offset );
pEntry->r_offset = convertor( pEntry->r_offset );
pEntry->r_info = convertor( pEntry->r_info );
}
//------------------------------------------------------------------------------
template <class T>
void generic_set_entry_rela( Elf_Xword index,
Elf64_Addr offset,
Elf_Word symbol,
unsigned type,
Elf_Sxword addend )
{
const endianess_convertor& convertor = elf_file.get_convertor();
T* pEntry = const_cast<T*>( reinterpret_cast<const T*>(
relocation_section->get_data() +
index * relocation_section->get_entry_size() ) );
if ( elf_file.get_class() == ELFCLASS32 ) {
pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type );
}
else {
pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type );
}
pEntry->r_offset = decltype( pEntry->r_offset )( offset );
pEntry->r_addend = decltype( pEntry->r_addend )( addend );
pEntry->r_offset = convertor( pEntry->r_offset );
pEntry->r_info = convertor( pEntry->r_info );
pEntry->r_addend = convertor( pEntry->r_addend );
}
//------------------------------------------------------------------------------
template <class T>
void generic_add_entry( Elf64_Addr offset, Elf_Xword info )
{
const endianess_convertor& convertor = elf_file.get_convertor();
T entry;
entry.r_offset = offset;
entry.r_info = info;
entry.r_offset = decltype( entry.r_offset )( offset );
entry.r_info = decltype( entry.r_info )( info );
entry.r_offset = convertor( entry.r_offset );
entry.r_info = convertor( entry.r_info );
relocation_section->append_data( reinterpret_cast<char*>( &entry ), sizeof( entry ) );
relocation_section->append_data( reinterpret_cast<char*>( &entry ),
sizeof( entry ) );
}
//------------------------------------------------------------------------------
template< class T >
//------------------------------------------------------------------------------
template <class T>
void
generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
{
@ -317,17 +440,20 @@ class relocation_section_accessor_template
entry.r_info = convertor( entry.r_info );
entry.r_addend = convertor( entry.r_addend );
relocation_section->append_data( reinterpret_cast<char*>( &entry ), sizeof( entry ) );
relocation_section->append_data( reinterpret_cast<char*>( &entry ),
sizeof( entry ) );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
private:
const elfio& elf_file;
S* relocation_section;
S* relocation_section = nullptr;
};
using relocation_section_accessor = relocation_section_accessor_template<section>;
using const_relocation_section_accessor = relocation_section_accessor_template<const section>;
using relocation_section_accessor =
relocation_section_accessor_template<section>;
using const_relocation_section_accessor =
relocation_section_accessor_template<const section>;
} // namespace ELFIO

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -25,321 +24,258 @@ THE SOFTWARE.
#define ELFIO_SECTION_HPP
#include <string>
#include <iostream>
#include "utils/logger.h"
#include <zlib.h>
#include <new>
#include <limits>
namespace ELFIO {
class section
{
friend class elfio;
public:
virtual ~section() {};
virtual ~section() = default;
ELFIO_GET_ACCESS_DECL ( Elf_Half, index );
ELFIO_GET_SET_ACCESS_DECL( std::string, name );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset );
ELFIO_GET_ACCESS_DECL ( Elf64_Off, offset );
size_t stream_size;
size_t get_stream_size() const
{
return stream_size;
}
ELFIO_GET_ACCESS_DECL( Elf_Half, index );
ELFIO_GET_SET_ACCESS_DECL( std::string, name );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset );
ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
void set_stream_size(size_t value)
{
stream_size = value;
}
virtual const char* get_data() const = 0;
virtual void set_data( const char* pData, Elf_Word size ) = 0;
virtual void set_data( const std::string& data ) = 0;
virtual void append_data( const char* pData, Elf_Word size ) = 0;
virtual void append_data( const std::string& data ) = 0;
virtual const char* get_data() const = 0;
virtual void set_data( const char* raw_data, Elf_Word size ) = 0;
virtual void set_data( const std::string& data ) = 0;
virtual void append_data( const char* raw_data, Elf_Word size ) = 0;
virtual void append_data( const std::string& data ) = 0;
virtual void
insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) = 0;
virtual void insert_data( Elf_Xword pos, const std::string& data ) = 0;
protected:
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
virtual void load( std::istream& stream,
std::streampos header_offset ) = 0;
virtual void save( std::ostream& stream,
std::streampos header_offset,
std::streampos data_offset ) = 0;
virtual bool is_address_initialized() const = 0;
virtual bool load( const char * pBuffer, size_t pBufferSize,
off_t header_offset) = 0;
virtual bool is_address_initialized() const = 0;
};
template< class T >
class section_impl : public section
template <class T> class section_impl : public section
{
public:
//------------------------------------------------------------------------------
section_impl( const endianess_convertor* convertor_ ) : convertor( convertor_ )
//------------------------------------------------------------------------------
section_impl( const endianess_convertor* convertor,
const std::shared_ptr<compression_interface>& compression )
: convertor( convertor ), compression( compression )
{
std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ), '\0' );
is_address_set = false;
data = 0;
data_size = 0;
}
//------------------------------------------------------------------------------
~section_impl()
{
delete [] data;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Section info functions
ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type );
ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags );
ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size );
ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link );
ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info );
ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign );
ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize );
ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name );
ELFIO_GET_ACCESS ( Elf64_Addr, address, header.sh_addr );
ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type );
ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags );
ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size );
ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link );
ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info );
ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign );
ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize );
ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name );
ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr );
//------------------------------------------------------------------------------
Elf_Half get_index() const override { return index; }
//------------------------------------------------------------------------------
std::string get_name() const override { return name; }
//------------------------------------------------------------------------------
Elf_Half
get_index() const
//------------------------------------------------------------------------------
void set_name( const std::string& name_prm ) override
{
return index;
this->name = name_prm;
}
//------------------------------------------------------------------------------
std::string
get_name() const
//------------------------------------------------------------------------------
void set_address( const Elf64_Addr& value ) override
{
return name;
}
//------------------------------------------------------------------------------
void
set_name( std::string name_ )
{
name = name_;
}
//------------------------------------------------------------------------------
void
set_address( Elf64_Addr value )
{
header.sh_addr = value;
header.sh_addr = (*convertor)( header.sh_addr );
header.sh_addr = decltype( header.sh_addr )( value );
header.sh_addr = ( *convertor )( header.sh_addr );
is_address_set = true;
}
//------------------------------------------------------------------------------
bool
is_address_initialized() const
//------------------------------------------------------------------------------
bool is_address_initialized() const override { return is_address_set; }
//------------------------------------------------------------------------------
const char* get_data() const override
{
return is_address_set;
return data.get();
}
//------------------------------------------------------------------------------
const char*
get_data() const
{
return data;
}
//------------------------------------------------------------------------------
void
set_data( const char* raw_data, Elf_Word size )
//------------------------------------------------------------------------------
void set_data( const char* raw_data, Elf_Word size ) override
{
if ( get_type() != SHT_NOBITS ) {
delete [] data;
data = new char[size];
if ( 0 != data && 0 != raw_data ) {
data = std::unique_ptr<char[]>( new ( std::nothrow ) char[size] );
if ( nullptr != data.get() && nullptr != raw_data ) {
data_size = size;
std::copy( raw_data, raw_data + size, data );
std::copy( raw_data, raw_data + size, data.get() );
}
else {
data_size = 0;
}
}
set_size( size );
set_size( data_size );
}
//------------------------------------------------------------------------------
void
set_data( const std::string& str_data )
//------------------------------------------------------------------------------
void set_data( const std::string& str_data ) override
{
return set_data( str_data.c_str(), (Elf_Word)str_data.size() );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void append_data( const char* raw_data, Elf_Word size ) override
{
insert_data( get_size(), raw_data, size );
}
//------------------------------------------------------------------------------
void append_data( const std::string& str_data ) override
{
return append_data( str_data.c_str(), (Elf_Word)str_data.size() );
}
//------------------------------------------------------------------------------
void
append_data( const char* raw_data, Elf_Word size )
insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) override
{
if ( get_type() != SHT_NOBITS ) {
if ( get_size() + size < data_size ) {
std::copy( raw_data, raw_data + size, data + get_size() );
char* d = data.get();
std::copy_backward( d + pos, d + get_size(),
d + get_size() + size );
std::copy( raw_data, raw_data + size, d + pos );
}
else {
data_size = 2*( data_size + size);
char* new_data;
new_data = new char[data_size];
data_size = 2 * ( data_size + size );
std::unique_ptr<char[]> new_data(
new ( std::nothrow ) char[data_size] );
if ( 0 != new_data ) {
std::copy( data, data + get_size(), new_data );
std::copy( raw_data, raw_data + size, new_data + get_size() );
delete [] data;
data = new_data;
if ( nullptr != new_data ) {
char* d = data.get();
std::copy( d, d + pos, new_data.get() );
std::copy( raw_data, raw_data + size,
new_data.get() + pos );
std::copy( d + pos, d + get_size(),
new_data.get() + pos + size );
data = std::move( new_data );
}
else {
size = 0;
}
}
set_size( get_size() + size );
}
}
//------------------------------------------------------------------------------
void
append_data( const std::string& str_data )
//------------------------------------------------------------------------------
void insert_data( Elf_Xword pos, const std::string& str_data ) override
{
return append_data( str_data.c_str(), (Elf_Word)str_data.size() );
return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
protected:
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset );
//------------------------------------------------------------------------------
void
set_index( Elf_Half value )
//------------------------------------------------------------------------------
void set_index( const Elf_Half& value ) override { index = value; }
bool is_compressed() const
{
index = value;
return ( ( get_flags() & SHF_RPX_DEFLATE ) ||
( get_flags() & SHF_COMPRESSED ) ) &&
compression != nullptr;
}
//------------------------------------------------------------------------------
void
load( std::istream& stream,
std::streampos header_offset )
//------------------------------------------------------------------------------
bool load( const char * pBuffer, size_t pBufferSize,
off_t header_offset) override
{
std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ), '\0' );
header = { };
stream.seekg ( 0, stream.end );
set_stream_size ( stream.tellg() );
if( header_offset + sizeof( header ) > pBufferSize ) {
return false;
}
memcpy( reinterpret_cast<char*>( &header ), pBuffer + header_offset, sizeof( header ) );
stream.seekg( header_offset );
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
bool ret = load_data(pBuffer, pBufferSize);
Elf_Xword size = get_size();
if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() && size < get_stream_size()) {
data = new char[size + 1];
if ( ( 0 != size ) && ( 0 != data ) ) {
stream.seekg( (*convertor)( header.sh_offset ) );
if (get_flags() & 0x08000000){
uint32_t uncompressed_size = size;
stream.read( (char *) &uncompressed_size, 4);
stream.read( data, size - 4);
char* uncompressedData = new char[uncompressed_size + 1];
int ret = 0;
z_stream s;
memset(&s, 0, sizeof(s));
s.zalloc = Z_NULL;
s.zfree = Z_NULL;
s.opaque = Z_NULL;
ret = inflateInit_(&s, ZLIB_VERSION, sizeof(s));
if (ret != Z_OK)
return;
s.avail_in = size - 4;
s.next_in = (Bytef *)data;
s.avail_out = uncompressed_size;
s.next_out = (Bytef *)&uncompressedData[0];
ret = inflate(&s, Z_FINISH);
if (ret != Z_OK && ret != Z_STREAM_END){
DEBUG_FUNCTION_LINE("NOOOO");
}
inflateEnd(&s);
delete [] data;
data = uncompressedData;
data_size = uncompressed_size;
set_size(uncompressed_size);
data[data_size] = 0; // Ensure data is ended with 0 to avoid oob read
}else{
stream.read( data, size );
data[size] = 0; // Ensure data is ended with 0 to avoid oob read
data_size = size;
}
}else{
set_size(0);
DEBUG_FUNCTION_LINE("Failed to allocate memory.");
if (ret && is_compressed() ) {
Elf_Xword size = get_size();
Elf_Xword uncompressed_size = 0;
auto decompressed_data = compression->inflate(
data.get(), convertor, size, uncompressed_size );
if ( decompressed_data != nullptr ) {
set_size( uncompressed_size );
data = std::move( decompressed_data );
}
}
return ret;
}
//------------------------------------------------------------------------------
void
save( std::ostream& stream,
std::streampos header_offset,
std::streampos data_offset )
bool load_data(const char * pBuffer, size_t pBufferSize) const
{
if ( 0 != get_index() ) {
header.sh_offset = data_offset;
header.sh_offset = (*convertor)( header.sh_offset );
Elf_Xword size = get_size();
if ( nullptr == data && SHT_NULL != get_type() &&
SHT_NOBITS != get_type() && size < pBufferSize ) {
data.reset( new ( std::nothrow ) char[size_t( size ) + 1] );
if ( ( 0 != size ) && ( nullptr != data ) ) {
auto offset = ( *convertor )( header.sh_offset );
if(offset + size > pBufferSize) {
data = nullptr;
return false;
}
memcpy( data.get(), pBuffer + offset, size );
// refresh size because it may have changed if we had to decompress data
size = get_size();
data.get()[size] =
0; // Ensure data is ended with 0 to avoid oob read
data_size = decltype( data_size )( size );
}
else {
data_size = 0;
}
}
save_header( stream, header_offset );
if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL &&
get_size() != 0 && data != 0 ) {
save_data( stream, data_offset );
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
void
save_header( std::ostream& stream,
std::streampos header_offset ) const
{
stream.seekp( header_offset );
stream.write( reinterpret_cast<const char*>( &header ), sizeof( header ) );
}
//------------------------------------------------------------------------------
void
save_data( std::ostream& stream,
std::streampos data_offset ) const
{
stream.seekp( data_offset );
stream.write( get_data(), get_size() );
}
//------------------------------------------------------------------------------
private:
T header;
Elf_Half index;
std::string name;
char* data;
Elf_Word data_size;
const endianess_convertor* convertor;
bool is_address_set;
//------------------------------------------------------------------------------
private:
T header = {};
Elf_Half index = 0;
std::string name;
mutable std::unique_ptr<char[]> data;
mutable Elf_Word data_size = 0;
const endianess_convertor* convertor = nullptr;
const std::shared_ptr<compression_interface> compression = nullptr;
bool is_address_set = false;
};
} // namespace ELFIO

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -24,109 +23,83 @@ THE SOFTWARE.
#ifndef ELFIO_SEGMENT_HPP
#define ELFIO_SEGMENT_HPP
#include <iostream>
#include <vector>
#include <new>
#include <limits>
namespace ELFIO {
class segment
{
friend class elfio;
public:
virtual ~segment() {};
ELFIO_GET_ACCESS_DECL ( Elf_Half, index );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address );
public:
virtual ~segment() = default;
ELFIO_GET_ACCESS_DECL( Elf_Half, index );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address );
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size );
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size );
ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
virtual const char* get_data() const = 0;
virtual Elf_Half add_section_index( Elf_Half index, Elf_Xword addr_align ) = 0;
virtual Elf_Half get_sections_num() const = 0;
virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0;
virtual bool is_offset_initialized() const = 0;
virtual Elf_Half add_section( section* psec, Elf_Xword addr_align ) = 0;
virtual Elf_Half add_section_index( Elf_Half index,
Elf_Xword addr_align ) = 0;
virtual Elf_Half get_sections_num() const = 0;
virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0;
virtual bool is_offset_initialized() const = 0;
protected:
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
virtual const std::vector<Elf_Half>& get_sections() const = 0;
virtual void load( std::istream& stream, std::streampos header_offset ) = 0;
virtual void save( std::ostream& stream, std::streampos header_offset,
std::streampos data_offset ) = 0;
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
virtual const std::vector<Elf_Half>& get_sections() const = 0;
virtual bool load( const char * pBuffer, size_t pBufferSize,
off_t header_offset ) = 0;
};
//------------------------------------------------------------------------------
template< class T >
class segment_impl : public segment
template <class T> class segment_impl : public segment
{
public:
//------------------------------------------------------------------------------
segment_impl( endianess_convertor* convertor_ ) :
stream_size( 0 ), index( 0 ), data( 0 ), convertor( convertor_ )
//------------------------------------------------------------------------------
segment_impl( const endianess_convertor* convertor )
: convertor( convertor )
{
is_offset_set = false;
std::fill_n( reinterpret_cast<char*>( &ph ), sizeof( ph ), '\0' );
}
//------------------------------------------------------------------------------
virtual ~segment_impl()
{
delete [] data;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Section info functions
ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type );
ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags );
ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align );
ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr );
ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr );
ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz );
ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz );
ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type );
ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags );
ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align );
ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr );
ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr );
ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz );
ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz );
ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset );
size_t stream_size;
//------------------------------------------------------------------------------
size_t
get_stream_size() const
//------------------------------------------------------------------------------
Elf_Half get_index() const override { return index; }
//------------------------------------------------------------------------------
const char* get_data() const override
{
return stream_size;
return data.get();
}
//------------------------------------------------------------------------------
void
set_stream_size(size_t value)
//------------------------------------------------------------------------------
Elf_Half add_section_index( Elf_Half sec_index,
Elf_Xword addr_align ) override
{
stream_size = value;
}
//------------------------------------------------------------------------------
Elf_Half
get_index() const
{
return index;
}
//------------------------------------------------------------------------------
const char*
get_data() const
{
return data;
}
//------------------------------------------------------------------------------
Elf_Half
add_section_index( Elf_Half sec_index, Elf_Xword addr_align )
{
sections.push_back( sec_index );
sections.emplace_back( sec_index );
if ( addr_align > get_align() ) {
set_align( addr_align );
}
@ -134,108 +107,100 @@ class segment_impl : public segment
return (Elf_Half)sections.size();
}
//------------------------------------------------------------------------------
Elf_Half
get_sections_num() const
//------------------------------------------------------------------------------
Elf_Half add_section( section* psec, Elf_Xword addr_align ) override
{
return add_section_index( psec->get_index(), addr_align );
}
//------------------------------------------------------------------------------
Elf_Half get_sections_num() const override
{
return (Elf_Half)sections.size();
}
//------------------------------------------------------------------------------
Elf_Half
get_section_index_at( Elf_Half num ) const
//------------------------------------------------------------------------------
Elf_Half get_section_index_at( Elf_Half num ) const override
{
if ( num < sections.size() ) {
return sections[num];
}
return Elf_Half(-1);
return Elf_Half( -1 );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
protected:
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
set_offset( Elf64_Off value )
//------------------------------------------------------------------------------
void set_offset( const Elf64_Off& value ) override
{
ph.p_offset = value;
ph.p_offset = (*convertor)( ph.p_offset );
ph.p_offset = decltype( ph.p_offset )( value );
ph.p_offset = ( *convertor )( ph.p_offset );
is_offset_set = true;
}
//------------------------------------------------------------------------------
bool
is_offset_initialized() const
{
return is_offset_set;
}
//------------------------------------------------------------------------------
bool is_offset_initialized() const override { return is_offset_set; }
//------------------------------------------------------------------------------
const std::vector<Elf_Half>&
get_sections() const
//------------------------------------------------------------------------------
const std::vector<Elf_Half>& get_sections() const override
{
return sections;
}
//------------------------------------------------------------------------------
void
set_index( Elf_Half value )
//------------------------------------------------------------------------------
void set_index( const Elf_Half& value ) override { index = value; }
//------------------------------------------------------------------------------
bool load( const char * pBuffer, size_t pBufferSize,
off_t header_offset) override
{
index = value;
}
//------------------------------------------------------------------------------
void
load( std::istream& stream,
std::streampos header_offset )
{
stream.seekg ( 0, stream.end );
set_stream_size ( stream.tellg() );
stream.seekg( header_offset );
stream.read( reinterpret_cast<char*>( &ph ), sizeof( ph ) );
if( header_offset + sizeof( ph ) > pBufferSize ) {
return false;
}
memcpy( reinterpret_cast<char*>( &ph ), pBuffer + header_offset, sizeof( ph ) );
is_offset_set = true;
if ( PT_NULL != get_type() && 0 != get_file_size() ) {
stream.seekg( (*convertor)( ph.p_offset ) );
Elf_Xword size = get_file_size();
return load_data(pBuffer, pBufferSize);
}
if ( size > get_stream_size() ) {
data = 0;
//------------------------------------------------------------------------------
bool load_data(const char * pBuffer, size_t pBufferSize) const
{
if ( PT_NULL == get_type() || 0 == get_file_size() ) {
return true;
}
auto offset = ( *convertor )( ph.p_offset );
Elf_Xword size = get_file_size();
if ( size > pBufferSize ) {
data = nullptr;
}
else {
data.reset( new ( std::nothrow ) char[(size_t)size + 1] );
if ( nullptr != data.get()) {
memcpy(data.get(), pBuffer + offset, size);
}
else {
data = new char[size + 1];
if ( 0 != data ) {
stream.read( data, size );
data[size] = 0;
}
data = nullptr;
return false;
}
}
return true;
}
//------------------------------------------------------------------------------
void save( std::ostream& stream,
std::streampos header_offset,
std::streampos data_offset )
{
ph.p_offset = data_offset;
ph.p_offset = (*convertor)(ph.p_offset);
stream.seekp( header_offset );
stream.write( reinterpret_cast<const char*>( &ph ), sizeof( ph ) );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
private:
T ph;
Elf_Half index;
char* data;
std::vector<Elf_Half> sections;
endianess_convertor* convertor;
bool is_offset_set;
T ph = {};
Elf_Half index = 0;
mutable std::unique_ptr<char[]> data;
std::vector<Elf_Half> sections;
const endianess_convertor* convertor = nullptr;
bool is_offset_set = false;
};
} // namespace ELFIO

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -31,70 +30,67 @@ THE SOFTWARE.
namespace ELFIO {
//------------------------------------------------------------------------------
template< class S >
class string_section_accessor_template
template <class S> class string_section_accessor_template
{
public:
//------------------------------------------------------------------------------
string_section_accessor_template( S* section_ ) :
string_section( section_ )
//------------------------------------------------------------------------------
explicit string_section_accessor_template( S* section )
: string_section( section )
{
}
//------------------------------------------------------------------------------
const char*
get_string( Elf_Word index ) const
//------------------------------------------------------------------------------
const char* get_string( Elf_Word index ) const
{
if ( string_section ) {
if ( index < string_section->get_size() ) {
const char* data = string_section->get_data();
if ( 0 != data ) {
const char* data = string_section->get_data();
if ( index < string_section->get_size() && nullptr != data ) {
size_t string_length =
strnlen( data + index, string_section->get_size() - index );
if ( string_length < ( string_section->get_size() - index ) )
return data + index;
}
}
}
return 0;
return nullptr;
}
//------------------------------------------------------------------------------
Elf_Word
add_string( const char* str )
//------------------------------------------------------------------------------
Elf_Word add_string( const char* str )
{
Elf_Word current_position = 0;
if (string_section) {
if ( string_section ) {
// Strings are addeded to the end of the current section data
current_position = (Elf_Word)string_section->get_size();
current_position =
static_cast<Elf_Word>( string_section->get_size() );
if ( current_position == 0 ) {
char empty_string = '\0';
string_section->append_data( &empty_string, 1 );
current_position++;
}
string_section->append_data( str, (Elf_Word)std::strlen( str ) + 1 );
string_section->append_data(
str, static_cast<Elf_Word>( std::strlen( str ) + 1 ) );
}
return current_position;
}
//------------------------------------------------------------------------------
Elf_Word
add_string( const std::string& str )
//------------------------------------------------------------------------------
Elf_Word add_string( const std::string& str )
{
return add_string( str.c_str() );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
private:
S* string_section;
};
using string_section_accessor = string_section_accessor_template<section>;
using const_string_section_accessor = string_section_accessor_template<const section>;
using const_string_section_accessor =
string_section_accessor_template<const section>;
} // namespace ELFIO

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -27,40 +26,51 @@ THE SOFTWARE.
namespace ELFIO {
//------------------------------------------------------------------------------
template< class S >
class symbol_section_accessor_template
template <class S> class symbol_section_accessor_template
{
public:
//------------------------------------------------------------------------------
symbol_section_accessor_template( const elfio& elf_file_, S* symbol_section_ ) :
elf_file( elf_file_ ),
symbol_section( symbol_section_ )
//------------------------------------------------------------------------------
explicit symbol_section_accessor_template( const elfio& elf_file,
S* symbol_section )
: elf_file( elf_file ), symbol_section( symbol_section )
{
find_hash_section();
}
//------------------------------------------------------------------------------
Elf_Xword
get_symbols_num() const
//------------------------------------------------------------------------------
Elf_Xword get_symbols_num() const
{
Elf_Xword nRet = 0;
if ( 0 != symbol_section->get_entry_size() ) {
nRet = symbol_section->get_size() / symbol_section->get_entry_size();
size_t minimum_symbol_size;
switch ( elf_file.get_class() ) {
case ELFCLASS32:
minimum_symbol_size = sizeof( Elf32_Sym );
break;
case ELFCLASS64:
minimum_symbol_size = sizeof( Elf64_Sym );
break;
default:
return nRet;
}
if ( symbol_section->get_entry_size() >= minimum_symbol_size ) {
nRet =
symbol_section->get_size() / symbol_section->get_entry_size();
}
return nRet;
}
//------------------------------------------------------------------------------
bool
get_symbol( Elf_Xword index,
std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
//------------------------------------------------------------------------------
bool get_symbol( Elf_Xword index,
std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
@ -76,46 +86,96 @@ class symbol_section_accessor_template
return ret;
}
//------------------------------------------------------------------------------
bool
get_symbol( const std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
//------------------------------------------------------------------------------
bool get_symbol( const std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
if ( 0 != get_hash_table_index() ) {
Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data();
Elf_Word nchain = *(const Elf_Word*)( hash_section->get_data() +
sizeof( Elf_Word ) );
Elf_Word val = elf_hash( (const unsigned char*)name.c_str() );
Elf_Word y = *(const Elf_Word*)( hash_section->get_data() +
( 2 + val % nbucket ) * sizeof( Elf_Word ) );
std::string str;
get_symbol( y, str, value, size, bind, type, section_index, other );
while ( str != name && STN_UNDEF != y && y < nchain ) {
y = *(const Elf_Word*)( hash_section->get_data() +
( 2 + nbucket + y ) * sizeof( Elf_Word ) );
get_symbol( y, str, value, size, bind, type, section_index, other );
if ( hash_section->get_type() == SHT_HASH ) {
ret = hash_lookup( name, value, size, bind, type, section_index,
other );
}
if ( str == name ) {
ret = true;
if ( hash_section->get_type() == SHT_GNU_HASH ||
hash_section->get_type() == DT_GNU_HASH ) {
if ( elf_file.get_class() == ELFCLASS32 ) {
ret = gnu_hash_lookup<uint32_t>(
name, value, size, bind, type, section_index, other );
}
else {
ret = gnu_hash_lookup<uint64_t>(
name, value, size, bind, type, section_index, other );
}
}
}
if ( !ret ) {
for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) {
std::string symbol_name;
if ( get_symbol( i, symbol_name, value, size, bind, type,
section_index, other ) ) {
if ( symbol_name == name ) {
ret = true;
}
}
}
}
return ret;
}
//------------------------------------------------------------------------------
Elf_Word
add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size,
unsigned char info, unsigned char other,
Elf_Half shndx )
//------------------------------------------------------------------------------
bool get_symbol( const Elf64_Addr& value,
std::string& name,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
const endianess_convertor& convertor = elf_file.get_convertor();
Elf_Xword idx = 0;
bool match = false;
Elf64_Addr v = 0;
if ( elf_file.get_class() == ELFCLASS32 ) {
match = generic_search_symbols<Elf32_Sym>(
[&]( const Elf32_Sym* sym ) {
return convertor( sym->st_value ) == value;
},
idx );
}
else {
match = generic_search_symbols<Elf64_Sym>(
[&]( const Elf64_Sym* sym ) {
return convertor( sym->st_value ) == value;
},
idx );
}
if ( match ) {
return get_symbol( idx, name, v, size, bind, type, section_index,
other );
}
return false;
}
//------------------------------------------------------------------------------
Elf_Word add_symbol( Elf_Word name,
Elf64_Addr value,
Elf_Xword size,
unsigned char info,
unsigned char other,
Elf_Half shndx )
{
Elf_Word nRet;
@ -129,110 +189,276 @@ class symbol_section_accessor_template
}
if ( elf_file.get_class() == ELFCLASS32 ) {
nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info, other,
shndx );
nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info,
other, shndx );
}
else {
nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info, other,
shndx );
nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info,
other, shndx );
}
return nRet;
}
//------------------------------------------------------------------------------
Elf_Word
add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size,
unsigned char bind, unsigned char type, unsigned char other,
Elf_Half shndx )
//------------------------------------------------------------------------------
Elf_Word add_symbol( Elf_Word name,
Elf64_Addr value,
Elf_Xword size,
unsigned char bind,
unsigned char type,
unsigned char other,
Elf_Half shndx )
{
return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, shndx );
return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other,
shndx );
}
//------------------------------------------------------------------------------
Elf_Word
add_symbol( string_section_accessor& pStrWriter, const char* str,
Elf64_Addr value, Elf_Xword size,
unsigned char info, unsigned char other,
Elf_Half shndx )
//------------------------------------------------------------------------------
Elf_Word add_symbol( string_section_accessor& pStrWriter,
const char* str,
Elf64_Addr value,
Elf_Xword size,
unsigned char info,
unsigned char other,
Elf_Half shndx )
{
Elf_Word index = pStrWriter.add_string( str );
return add_symbol( index, value, size, info, other, shndx );
}
//------------------------------------------------------------------------------
Elf_Word
add_symbol( string_section_accessor& pStrWriter, const char* str,
Elf64_Addr value, Elf_Xword size,
unsigned char bind, unsigned char type, unsigned char other,
Elf_Half shndx )
//------------------------------------------------------------------------------
Elf_Word add_symbol( string_section_accessor& pStrWriter,
const char* str,
Elf64_Addr value,
Elf_Xword size,
unsigned char bind,
unsigned char type,
unsigned char other,
Elf_Half shndx )
{
return add_symbol( pStrWriter, str, value, size, ELF_ST_INFO( bind, type ), other, shndx );
return add_symbol( pStrWriter, str, value, size,
ELF_ST_INFO( bind, type ), other, shndx );
}
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
void
find_hash_section()
//------------------------------------------------------------------------------
Elf_Xword arrange_local_symbols(
std::function<void( Elf_Xword first, Elf_Xword second )> func =
nullptr )
{
Elf_Xword nRet = 0;
if ( elf_file.get_class() == ELFCLASS32 ) {
nRet = generic_arrange_local_symbols<Elf32_Sym>( func );
}
else {
nRet = generic_arrange_local_symbols<Elf64_Sym>( func );
}
return nRet;
}
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
void find_hash_section()
{
hash_section = 0;
hash_section_index = 0;
Elf_Half nSecNo = elf_file.sections.size();
for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) {
for ( Elf_Half i = 0; i < nSecNo; ++i ) {
const section* sec = elf_file.sections[i];
if ( sec->get_link() == symbol_section->get_index() ) {
if ( sec->get_link() == symbol_section->get_index() &&
( sec->get_type() == SHT_HASH ||
sec->get_type() == SHT_GNU_HASH ||
sec->get_type() == DT_GNU_HASH ) ) {
hash_section = sec;
hash_section_index = i;
break;
}
}
}
//------------------------------------------------------------------------------
Elf_Half
get_string_table_index() const
//------------------------------------------------------------------------------
Elf_Half get_string_table_index() const
{
return (Elf_Half)symbol_section->get_link();
}
//------------------------------------------------------------------------------
Elf_Half
get_hash_table_index() const
//------------------------------------------------------------------------------
Elf_Half get_hash_table_index() const { return hash_section_index; }
//------------------------------------------------------------------------------
bool hash_lookup( const std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
return hash_section_index;
bool ret = false;
const endianess_convertor& convertor = elf_file.get_convertor();
Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data();
nbucket = convertor( nbucket );
Elf_Word nchain =
*(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) );
nchain = convertor( nchain );
Elf_Word val = elf_hash( (const unsigned char*)name.c_str() );
Elf_Word y =
*(const Elf_Word*)( hash_section->get_data() +
( 2 + val % nbucket ) * sizeof( Elf_Word ) );
y = convertor( y );
std::string str;
get_symbol( y, str, value, size, bind, type, section_index, other );
while ( str != name && STN_UNDEF != y && y < nchain ) {
y = *(const Elf_Word*)( hash_section->get_data() +
( 2 + nbucket + y ) * sizeof( Elf_Word ) );
y = convertor( y );
get_symbol( y, str, value, size, bind, type, section_index, other );
}
if ( str == name ) {
ret = true;
}
return ret;
}
//------------------------------------------------------------------------------
template< class T >
bool
generic_get_symbol( Elf_Xword index,
std::string& name, Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind, unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
//------------------------------------------------------------------------------
template <class T>
bool gnu_hash_lookup( const std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
const endianess_convertor& convertor = elf_file.get_convertor();
uint32_t nbuckets = *( (uint32_t*)hash_section->get_data() + 0 );
uint32_t symoffset = *( (uint32_t*)hash_section->get_data() + 1 );
uint32_t bloom_size = *( (uint32_t*)hash_section->get_data() + 2 );
uint32_t bloom_shift = *( (uint32_t*)hash_section->get_data() + 3 );
nbuckets = convertor( nbuckets );
symoffset = convertor( symoffset );
bloom_size = convertor( bloom_size );
bloom_shift = convertor( bloom_shift );
T* bloom_filter =
(T*)( hash_section->get_data() + 4 * sizeof( uint32_t ) );
uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() );
uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size;
T bloom_bits =
( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) |
( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) );
if ( ( convertor( bloom_filter[bloom_index] ) & bloom_bits ) !=
bloom_bits )
return ret;
uint32_t bucket = hash % nbuckets;
auto* buckets =
(uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) +
bloom_size * sizeof( T ) );
auto* chains =
(uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) +
bloom_size * sizeof( T ) +
nbuckets * sizeof( uint32_t ) );
if ( convertor( buckets[bucket] ) >= symoffset ) {
uint32_t chain_index = convertor( buckets[bucket] ) - symoffset;
uint32_t chain_hash = convertor( chains[chain_index] );
std::string symname;
while ( true ) {
if ( ( chain_hash >> 1 ) == ( hash >> 1 ) &&
get_symbol( chain_index + symoffset, symname, value, size,
bind, type, section_index, other ) &&
name == symname ) {
ret = true;
break;
}
if ( chain_hash & 1 )
break;
chain_hash = convertor( chains[++chain_index] );
}
}
return ret;
}
//------------------------------------------------------------------------------
template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const
{
if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
const T* pSym = reinterpret_cast<const T*>(
symbol_section->get_data() +
index * symbol_section->get_entry_size() );
return pSym;
}
return nullptr;
}
//------------------------------------------------------------------------------
template <class T>
bool generic_search_symbols( std::function<bool( const T* )> match,
Elf_Xword& idx ) const
{
for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) {
const T* symPtr = generic_get_symbol_ptr<T>( i );
if ( symPtr == nullptr )
return false;
if ( match( symPtr ) ) {
idx = i;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
template <class T>
bool generic_get_symbol( Elf_Xword index,
std::string& name,
Elf64_Addr& value,
Elf_Xword& size,
unsigned char& bind,
unsigned char& type,
Elf_Half& section_index,
unsigned char& other ) const
{
bool ret = false;
if ( index < get_symbols_num() ) {
if ( nullptr != symbol_section->get_data() &&
index < get_symbols_num() ) {
const T* pSym = reinterpret_cast<const T*>(
symbol_section->get_data() +
index * symbol_section->get_entry_size() );
index * symbol_section->get_entry_size() );
const endianess_convertor& convertor = elf_file.get_convertor();
section* string_section = elf_file.sections[get_string_table_index()];
section* string_section =
elf_file.sections[get_string_table_index()];
string_section_accessor str_reader( string_section );
const char* pStr = str_reader.get_string( convertor( pSym->st_name ) );
if ( 0 != pStr ) {
const char* pStr =
str_reader.get_string( convertor( pSym->st_name ) );
if ( nullptr != pStr ) {
name = pStr;
}
value = convertor( pSym->st_value );
size = convertor( pSym->st_size );
bind = ELF_ST_BIND( pSym->st_info );
type = ELF_ST_TYPE( pSym->st_info );
value = convertor( pSym->st_value );
size = convertor( pSym->st_size );
bind = ELF_ST_BIND( pSym->st_info );
type = ELF_ST_TYPE( pSym->st_info );
section_index = convertor( pSym->st_shndx );
other = pSym->st_other;
other = pSym->st_other;
ret = true;
}
@ -240,20 +466,22 @@ class symbol_section_accessor_template
return ret;
}
//------------------------------------------------------------------------------
template< class T >
Elf_Word
generic_add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size,
unsigned char info, unsigned char other,
Elf_Half shndx )
//------------------------------------------------------------------------------
template <class T>
Elf_Word generic_add_symbol( Elf_Word name,
Elf64_Addr value,
Elf_Xword size,
unsigned char info,
unsigned char other,
Elf_Half shndx )
{
const endianess_convertor& convertor = elf_file.get_convertor();
T entry;
entry.st_name = convertor( name );
entry.st_value = value;
entry.st_value = decltype( entry.st_value )( value );
entry.st_value = convertor( entry.st_value );
entry.st_size = size;
entry.st_size = decltype( entry.st_size )( size );
entry.st_size = convertor( entry.st_size );
entry.st_info = convertor( info );
entry.st_other = convertor( other );
@ -262,21 +490,71 @@ class symbol_section_accessor_template
symbol_section->append_data( reinterpret_cast<char*>( &entry ),
sizeof( entry ) );
Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1;
Elf_Word nRet =
Elf_Word( symbol_section->get_size() / sizeof( entry ) - 1 );
return nRet;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
template <class T>
Elf_Xword generic_arrange_local_symbols(
std::function<void( Elf_Xword first, Elf_Xword second )> func )
{
const endianess_convertor& convertor = elf_file.get_convertor();
Elf_Word first_not_local =
1; // Skip the first entry. It is always NOTYPE
Elf_Xword current = 0;
Elf_Xword count = get_symbols_num();
while ( true ) {
T* p1 = nullptr;
T* p2 = nullptr;
while ( first_not_local < count ) {
p1 = const_cast<T*>(
generic_get_symbol_ptr<T>( first_not_local ) );
if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL )
break;
++first_not_local;
}
current = first_not_local + 1;
while ( current < count ) {
p2 = const_cast<T*>( generic_get_symbol_ptr<T>( current ) );
if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL )
break;
++current;
}
if ( first_not_local < count && current < count ) {
if ( func )
func( first_not_local, current );
std::swap( *p1, *p2 );
}
else {
// Update 'info' field of the section
symbol_section->set_info( first_not_local );
break;
}
}
return first_not_local;
}
//------------------------------------------------------------------------------
private:
const elfio& elf_file;
S* symbol_section;
Elf_Half hash_section_index;
const section* hash_section;
Elf_Half hash_section_index{ 0 };
const section* hash_section{ nullptr };
};
using symbol_section_accessor = symbol_section_accessor_template<section>;
using const_symbol_section_accessor = symbol_section_accessor_template<const section>;
using const_symbol_section_accessor =
symbol_section_accessor_template<const section>;
} // namespace ELFIO

View File

@ -1,6 +1,5 @@
// clang-format off
/*
Copyright (C) 2001-2015 by Serge Lamikhov-Center
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -24,158 +23,129 @@ THE SOFTWARE.
#ifndef ELFIO_UTILS_HPP
#define ELFIO_UTILS_HPP
#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \
TYPE get_##NAME() const \
{ \
return (*convertor)( FIELD ); \
}
#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \
void set_##NAME( TYPE value ) \
{ \
FIELD = value; \
FIELD = (*convertor)( FIELD ); \
}
#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \
TYPE get_##NAME() const \
{ \
return (*convertor)( FIELD ); \
} \
void set_##NAME( TYPE value ) \
{ \
FIELD = value; \
FIELD = (*convertor)( FIELD ); \
}
#include <cstdint>
#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) \
virtual TYPE get_##NAME() const = 0
#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0
#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \
virtual void set_##NAME( TYPE value ) = 0
virtual void set_##NAME( const TYPE& value ) = 0
#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \
virtual TYPE get_##NAME() const = 0; \
virtual void set_##NAME( TYPE value ) = 0
#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \
virtual TYPE get_##NAME() const = 0; \
virtual void set_##NAME( const TYPE& value ) = 0
#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \
TYPE get_##NAME() const override { return ( *convertor )( FIELD ); }
#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \
void set_##NAME( const TYPE& value ) override \
{ \
FIELD = decltype( FIELD )( value ); \
FIELD = ( *convertor )( FIELD ); \
}
#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \
TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } \
void set_##NAME( const TYPE& value ) override \
{ \
FIELD = decltype( FIELD )( value ); \
FIELD = ( *convertor )( FIELD ); \
}
namespace ELFIO {
//------------------------------------------------------------------------------
class endianess_convertor {
class endianess_convertor
{
public:
//------------------------------------------------------------------------------
endianess_convertor()
{
need_conversion = false;
}
//------------------------------------------------------------------------------
void
setup( unsigned char elf_file_encoding )
//------------------------------------------------------------------------------
void setup( unsigned char elf_file_encoding )
{
need_conversion = ( elf_file_encoding != get_host_encoding() );
}
//------------------------------------------------------------------------------
uint64_t
operator()( uint64_t value ) const
//------------------------------------------------------------------------------
uint64_t operator()( uint64_t value ) const
{
if ( !need_conversion ) {
return value;
}
value = ( ( value & 0x00000000000000FFuLL ) << 56 ) |
( ( value & 0x000000000000FF00uLL ) << 40 ) |
( ( value & 0x0000000000FF0000uLL ) << 24 ) |
( ( value & 0x00000000FF000000uLL ) << 8 ) |
( ( value & 0x000000FF00000000uLL ) >> 8 ) |
( ( value & 0x0000FF0000000000uLL ) >> 24 ) |
( ( value & 0x00FF000000000000uLL ) >> 40 ) |
( ( value & 0xFF00000000000000uLL ) >> 56 );
return value;
}
//------------------------------------------------------------------------------
int64_t operator()( int64_t value ) const
{
if ( !need_conversion ) {
return value;
}
return (int64_t)( *this )( (uint64_t)value );
}
//------------------------------------------------------------------------------
uint32_t operator()( uint32_t value ) const
{
if ( !need_conversion ) {
return value;
}
value =
( ( value & 0x00000000000000FFull ) << 56 ) |
( ( value & 0x000000000000FF00ull ) << 40 ) |
( ( value & 0x0000000000FF0000ull ) << 24 ) |
( ( value & 0x00000000FF000000ull ) << 8 ) |
( ( value & 0x000000FF00000000ull ) >> 8 ) |
( ( value & 0x0000FF0000000000ull ) >> 24 ) |
( ( value & 0x00FF000000000000ull ) >> 40 ) |
( ( value & 0xFF00000000000000ull ) >> 56 );
( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) |
( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 );
return value;
}
//------------------------------------------------------------------------------
int64_t
operator()( int64_t value ) const
//------------------------------------------------------------------------------
int32_t operator()( int32_t value ) const
{
if ( !need_conversion ) {
return value;
}
return (int64_t)(*this)( (uint64_t)value );
return (int32_t)( *this )( (uint32_t)value );
}
//------------------------------------------------------------------------------
uint32_t
operator()( uint32_t value ) const
//------------------------------------------------------------------------------
uint16_t operator()( uint16_t value ) const
{
if ( !need_conversion ) {
return value;
}
value =
( ( value & 0x000000FF ) << 24 ) |
( ( value & 0x0000FF00 ) << 8 ) |
( ( value & 0x00FF0000 ) >> 8 ) |
( ( value & 0xFF000000 ) >> 24 );
(uint16_t)( ( value & 0x00FF ) << 8 ) | ( ( value & 0xFF00 ) >> 8 );
return value;
}
//------------------------------------------------------------------------------
int32_t
operator()( int32_t value ) const
//------------------------------------------------------------------------------
int16_t operator()( int16_t value ) const
{
if ( !need_conversion ) {
return value;
}
return (int32_t)(*this)( (uint32_t)value );
return (int16_t)( *this )( (uint16_t)value );
}
//------------------------------------------------------------------------------
uint16_t
operator()( uint16_t value ) const
{
if ( !need_conversion ) {
return value;
}
value =
( ( value & 0x00FF ) << 8 ) |
( ( value & 0xFF00 ) >> 8 );
//------------------------------------------------------------------------------
int8_t operator()( int8_t value ) const { return value; }
return value;
}
//------------------------------------------------------------------------------
uint8_t operator()( uint8_t value ) const { return value; }
//------------------------------------------------------------------------------
int16_t
operator()( int16_t value ) const
{
if ( !need_conversion ) {
return value;
}
return (int16_t)(*this)( (uint16_t)value );
}
//------------------------------------------------------------------------------
int8_t
operator()( int8_t value ) const
{
return value;
}
//------------------------------------------------------------------------------
uint8_t
operator()( uint8_t value ) const
{
return value;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
private:
//------------------------------------------------------------------------------
unsigned char
get_host_encoding() const
//------------------------------------------------------------------------------
unsigned char get_host_encoding() const
{
static const int tmp = 1;
if ( 1 == *(const char*)&tmp ) {
if ( 1 == *reinterpret_cast<const char*>( &tmp ) ) {
return ELFDATA2LSB;
}
else {
@ -183,20 +153,17 @@ class endianess_convertor {
}
}
//------------------------------------------------------------------------------
private:
bool need_conversion;
//------------------------------------------------------------------------------
bool need_conversion = false;
};
//------------------------------------------------------------------------------
inline
uint32_t
elf_hash( const unsigned char *name )
inline uint32_t elf_hash( const unsigned char* name )
{
uint32_t h = 0, g;
while ( *name ) {
h = (h << 4) + *name++;
uint32_t h = 0;
uint32_t g = 0;
while ( *name != '\0' ) {
h = ( h << 4 ) + *name++;
g = h & 0xf0000000;
if ( g != 0 )
h ^= g >> 24;
@ -205,6 +172,83 @@ elf_hash( const unsigned char *name )
return h;
}
//------------------------------------------------------------------------------
inline uint32_t elf_gnu_hash( const unsigned char* s )
{
uint32_t h = 0x1505;
for ( unsigned char c = *s; c != '\0'; c = *++s )
h = ( h << 5 ) + h + c;
return h;
}
//------------------------------------------------------------------------------
inline std::string to_hex_string( uint64_t value )
{
std::string str;
while ( value ) {
auto digit = value & 0xF;
if ( digit < 0xA ) {
str = char( '0' + digit ) + str;
}
else {
str = char( 'A' + digit - 0xA ) + str;
}
value >>= 4;
}
return "0x" + str;
}
//------------------------------------------------------------------------------
inline void adjust_stream_size( std::ostream& stream, std::streamsize offset )
{
stream.seekp( 0, std::ios_base::end );
if ( stream.tellp() < offset ) {
std::streamsize size = offset - stream.tellp();
stream.write( std::string( size_t( size ), '\0' ).c_str(), size );
}
stream.seekp( offset );
}
/**
* Consumers should write an implementation of this class and pass an instance of it to the ELFIO::elfio constructor.
*/
class compression_interface
{
public:
virtual ~compression_interface() = default;
/**
* decompresses a compressed section
*
* @param data the buffer of compressed data
* @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness.
* @param compressed_size the size of the data buffer, in bytes
* @param decompressed_size a reference to a variable where the decompressed buffer size will be stored.
* @returns a smart pointer to the decompressed data.
*/
virtual std::unique_ptr<char[]>
inflate( const char* data,
const endianess_convertor* convertor,
Elf_Xword compressed_size,
Elf_Xword& uncompressed_size ) const = 0;
/**
* compresses a section
*
* @param data the buffer of uncompressed data
* @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness.
* @param decompressed_size the size of the data buffer, in bytes
* @param compressed_size a reference to a variable where the compressed buffer size will be stored.
* @returns a smart pointer to the compressed data.
*/
virtual std::unique_ptr<char[]>
deflate( const char* data,
const endianess_convertor* convertor,
Elf_Xword decompressed_size,
Elf_Xword& compressed_size ) const = 0;
};
} // namespace ELFIO
#endif // ELFIO_UTILS_HPP

View File

@ -0,0 +1 @@
#define ELFIO_VERSION "3.12"

View File

@ -0,0 +1,179 @@
/*
Copyright (C) 2001-present by Serge Lamikhov-Center
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef ELFIO_VERSYM_HPP
#define ELFIO_VERSYM_HPP
namespace ELFIO {
//------------------------------------------------------------------------------
template <class S> class versym_section_accessor_template
{
public:
//------------------------------------------------------------------------------
explicit versym_section_accessor_template( S* section )
: versym_section( section )
{
if ( section != nullptr ) {
entries_num = decltype( entries_num )( section->get_size() /
sizeof( Elf_Half ) );
}
}
//------------------------------------------------------------------------------
Elf_Word get_entries_num() const
{
if ( versym_section ) {
return entries_num;
}
return 0;
}
//------------------------------------------------------------------------------
bool get_entry( Elf_Word no, Elf_Half& value ) const
{
if ( versym_section && ( no < get_entries_num() ) ) {
value = ( (Elf_Half*)versym_section->get_data() )[no];
return true;
}
return false;
}
//------------------------------------------------------------------------------
bool modify_entry( Elf_Word no, Elf_Half value )
{
if ( versym_section && ( no < get_entries_num() ) ) {
( (Elf_Half*)versym_section->get_data() )[no] = value;
return true;
}
return false;
}
//------------------------------------------------------------------------------
bool add_entry( Elf_Half value )
{
if ( !versym_section ) {
return false;
}
versym_section->append_data( (const char*)&value, sizeof( Elf_Half ) );
++entries_num;
return true;
}
//------------------------------------------------------------------------------
private:
S* versym_section = nullptr;
Elf_Word entries_num = 0;
};
using versym_section_accessor = versym_section_accessor_template<section>;
using const_versym_section_accessor =
versym_section_accessor_template<const section>;
//------------------------------------------------------------------------------
template <class S> class versym_r_section_accessor_template
{
public:
//------------------------------------------------------------------------------
versym_r_section_accessor_template( const elfio& elf_file,
S* versym_r_section )
: elf_file( elf_file ), versym_r_section( versym_r_section ),
entries_num( 0 )
{
// Find .dynamic section
const section* dynamic_section = elf_file.sections[".dynamic"];
if ( dynamic_section == nullptr ) {
return;
}
const_dynamic_section_accessor dynamic_section_acc( elf_file,
dynamic_section );
Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num();
for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) {
Elf_Xword tag;
Elf_Xword value;
std::string str;
if ( dynamic_section_acc.get_entry( i, tag, value, str ) &&
tag == DT_VERNEEDNUM ) {
entries_num = (Elf_Word)value;
break;
}
}
}
//------------------------------------------------------------------------------
Elf_Word get_entries_num() const { return entries_num; }
//------------------------------------------------------------------------------
bool get_entry( Elf_Word no,
Elf_Half& version,
std::string& file_name,
Elf_Word& hash,
Elf_Half& flags,
Elf_Half& other,
std::string& dep_name ) const
{
if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) {
return false;
}
const_string_section_accessor string_section_acc(
elf_file.sections[versym_r_section->get_link()] );
Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data();
Elfxx_Vernaux* veraux =
(Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux );
for ( Elf_Word i = 0; i < no; ++i ) {
verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next );
veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux );
}
version = verneed->vn_version;
file_name = string_section_acc.get_string( verneed->vn_file );
hash = veraux->vna_hash;
flags = veraux->vna_flags;
other = veraux->vna_other;
dep_name = string_section_acc.get_string( veraux->vna_name );
return true;
}
//------------------------------------------------------------------------------
private:
const elfio& elf_file;
S* versym_r_section = nullptr;
Elf_Word entries_num = 0;
};
using versym_r_section_accessor = versym_r_section_accessor_template<section>;
using const_versym_r_section_accessor =
versym_r_section_accessor_template<const section>;
} // namespace ELFIO
#endif // ELFIO_VERSYM_HPP

View File

@ -7,14 +7,17 @@
#include <coreinit/filesystem_fsa.h>
#include <coreinit/foreground.h>
#include <coreinit/ios.h>
#include <coreinit/savedframe.h>
#include <coreinit/screen.h>
#include <coreinit/title.h>
#include <elfio/elfio.hpp>
#include <fcntl.h>
#include <gx2/display.h>
#include <gx2/state.h>
#include <malloc.h>
#include <memory>
#include <nn/act/client_cpp.h>
#include <nsysccr/cdc.h>
#include <proc_ui/procui.h>
#include <sysapp/launch.h>
#include <sysapp/title.h>
@ -30,14 +33,18 @@
#include "kernel.h"
#include "module/ModuleDataFactory.h"
#include "utils/DrawUtils.h"
#include "utils/FileUtils.h"
#include "utils/InputUtils.h"
#include "utils/OnLeavingScope.h"
#include "utils/PairUtils.h"
#include "utils/utils.h"
#include "utils/wiiu_zlib.hpp"
#include "version.h"
// clang-format off
#define MEMORY_REGION_START 0x00A00000
#define MEMORY_REGION_SIZE 0x00600000
#define MEMORY_REGION_END (MEMORY_REGION_START + MEMORY_REGION_SIZE)
#define ENVIRONMENT_LOADER_VERSION "v0.3.2"
#define AUTOBOOT_CONFIG_PATH "fs:/vol/external01/wiiu/environments/default.cfg"
// clang-format on
#define MEMORY_REGION_START 0x00800000
#define AUTOBOOT_CONFIG_PATH "fs:/vol/external01/wiiu/environments/default.cfg"
bool CheckRunning() {
switch (ProcUIProcessMessages(true)) {
@ -90,6 +97,8 @@ bool writeFileContent(const std::string &path, const std::string &content) {
extern "C" void __fini();
extern "C" void __init_wut_malloc();
void LoadAndRunModule(std::string_view filepath, std::string_view environment_path);
void ClearSavedFrameBuffers();
int main(int argc, char **argv) {
// We need to call __init_wut_malloc somewhere so wut_malloc will be used for the memory allocation.
@ -108,28 +117,22 @@ int main(int argc, char **argv) {
DEBUG_FUNCTION_LINE("Hello from EnvironmentLoader!");
char environmentPath[0x100];
memset(environmentPath, 0, sizeof(environmentPath));
auto handle = IOS_Open("/dev/mcp", IOS_OPEN_READ);
char environmentPathFromIOSU[0x100] = {};
auto handle = IOS_Open("/dev/mcp", IOS_OPEN_READ);
if (handle >= 0) {
int in = 0xF9; // IPC_CUSTOM_COPY_ENVIRONMENT_PATH
if (IOS_Ioctl(handle, 100, &in, sizeof(in), environmentPath, sizeof(environmentPath)) == IOS_ERROR_OK) {
DEBUG_FUNCTION_LINE("Boot into %s", environmentPath);
if (IOS_Ioctl(handle, 100, &in, sizeof(in), environmentPathFromIOSU, sizeof(environmentPathFromIOSU)) == IOS_ERROR_OK) {
DEBUG_FUNCTION_LINE("Boot into %s", environmentPathFromIOSU);
}
IOS_Close(handle);
}
// We substract 0x100 to be safe.
uint32_t textSectionStart = textStart() - 0x100;
auto gModuleData = (module_information_t *) (textSectionStart - sizeof(module_information_t));
bool noEnvironmentsFound = false;
bool shownMenu = false;
std::string environment_path = std::string(environmentPath);
if (strncmp(environmentPath, "fs:/vol/external01/wiiu/environments/", strlen("fs:/vol/external01/wiiu/environments/")) != 0) {
std::string environmentPath = std::string(environmentPathFromIOSU);
if (!environmentPath.starts_with("fs:/vol/external01/wiiu/environments/")) { // If the environment path in IOSU is empty or unexpected, read config
DirList environmentDirs("fs:/vol/external01/wiiu/environments/", nullptr, DirList::Dirs, 1);
std::map<std::string, std::string> environmentPaths;
@ -146,9 +149,9 @@ int main(int argc, char **argv) {
for (auto const &[key, val] : environmentPaths) {
if (res.value() == key) {
DEBUG_FUNCTION_LINE("Found environment %s from config at index %d", res.value().c_str(), i);
autobootIndex = i;
environment_path = val;
forceMenu = false;
autobootIndex = i;
environmentPath = val;
forceMenu = false;
break;
}
i++;
@ -157,29 +160,41 @@ int main(int argc, char **argv) {
DEBUG_FUNCTION_LINE_ERR("No config found");
}
VPADReadError err;
VPADStatus vpad_data;
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &err);
InputUtils::Init();
uint32_t btn = 0;
if (err == VPAD_READ_SUCCESS) {
btn = vpad_data.hold | vpad_data.trigger;
}
InputUtils::InputData input = InputUtils::getControllerInput();
if (forceMenu || (btn & VPAD_BUTTON_X) == VPAD_BUTTON_X) {
if (forceMenu || ((input.trigger | input.hold) & VPAD_BUTTON_X) == VPAD_BUTTON_X) {
shownMenu = true;
DEBUG_FUNCTION_LINE_VERBOSE("Open menu!");
environment_path = EnvironmentSelectionScreen(environmentPaths, autobootIndex);
environmentPath = EnvironmentSelectionScreen(environmentPaths, autobootIndex);
if (environmentPaths.empty()) {
noEnvironmentsFound = true;
} else {
DEBUG_FUNCTION_LINE_VERBOSE("Selected %s", environment_path.c_str());
DEBUG_FUNCTION_LINE_VERBOSE("Selected %s", environmentPath.c_str());
}
} else {
}
InputUtils::DeInit();
}
if (!shownMenu) {
// Clear saved frame buffer to reduce screen corruption
ClearSavedFrameBuffers();
OSScreenInit();
// Call GX2Init to shut down OSScreen
GX2Init(nullptr);
GX2SetTVEnable(FALSE);
GX2SetDRCEnable(FALSE);
}
RevertMainHook();
if (!noEnvironmentsFound) {
DirList setupModules(environment_path + "/modules/setup", ".rpx", DirList::Files, 1);
DirList setupModules(environmentPath + "/modules/setup", ".rpx", DirList::Files, 1);
setupModules.SortList();
for (int i = 0; i < setupModules.GetFilecount(); i++) {
@ -189,43 +204,9 @@ int main(int argc, char **argv) {
continue;
}
// Some module may unmount the sd card on exit.
FSAInit();
auto client = FSAAddClient(nullptr);
if (client) {
FSAMount(client, "/dev/sdcard01", "/vol/external01", static_cast<FSAMountFlags>(0), nullptr, 0);
FSADelClient(client);
}
uint32_t destination_address_end = ((uint32_t) gModuleData) & 0xFFFF0000;
memset((void *) gModuleData, 0, sizeof(module_information_t));
DEBUG_FUNCTION_LINE("Trying to run %s.", setupModules.GetFilepath(i), destination_address_end, ((uint32_t) gModuleData) - MEMORY_REGION_START);
auto moduleData = ModuleDataFactory::load(setupModules.GetFilepath(i), destination_address_end, ((uint32_t) gModuleData) - MEMORY_REGION_START, gModuleData->trampolines,
DYN_LINK_TRAMPOLIN_LIST_LENGTH);
if (!moduleData) {
DEBUG_FUNCTION_LINE_ERR("Failed to load %s", setupModules.GetFilepath(i));
OSFatal("EnvironmentLoader: Failed to load module");
continue;
}
DEBUG_FUNCTION_LINE("Loaded module data");
if (!ElfUtils::doRelocation(moduleData.value()->getRelocationDataList(), gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) {
DEBUG_FUNCTION_LINE_ERR("Relocations failed");
OSFatal("EnvironmentLoader: Relocations failed");
} else {
DEBUG_FUNCTION_LINE("Relocation done");
}
DCFlushRange((void *) moduleData.value()->getStartAddress(), moduleData.value()->getEndAddress() - moduleData.value()->getStartAddress());
ICInvalidateRange((void *) moduleData.value()->getStartAddress(), moduleData.value()->getEndAddress() - moduleData.value()->getStartAddress());
DEBUG_FUNCTION_LINE("Calling entrypoint @%08X", moduleData.value()->getEntrypoint());
char *arr[1];
arr[0] = (char *) environment_path.c_str();
// clang-format off
((int(*)(int, char **)) moduleData.value()->getEntrypoint())(1, arr);
// clang-format on
DEBUG_FUNCTION_LINE("Back from module");
LoadAndRunModule(setupModules.GetFilepath(i), environmentPath);
}
} else {
DEBUG_FUNCTION_LINE("Return to Wii U Menu");
ProcUIInit(OSSavesDone_ReadyToRelease);
@ -258,17 +239,239 @@ int main(int argc, char **argv) {
return 0;
}
#define COLOR_WHITE Color(0xffffffff)
#define COLOR_BLACK Color(0, 0, 0, 255)
#define COLOR_RED Color(237, 28, 36, 255)
#define COLOR_BACKGROUND Color(0, 40, 100, 255)
#define COLOR_TEXT COLOR_WHITE
#define COLOR_TEXT2 Color(0xB3ffffff)
#define COLOR_AUTOBOOT Color(0xaeea00ff)
#define COLOR_BORDER Color(204, 204, 204, 255)
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4ff)
std::optional<HeapWrapper> GetHeapFromMappedMemory(uint32_t heapSize) {
void *(*MEMAllocFromDefaultHeapExForThreads)(uint32_t size, int align) = nullptr;
void (*MEMFreeToDefaultHeapForThreads)(void *ptr) = nullptr;
// Let's try to get the memalign and free functions from the memorymapping module.
OSDynLoad_Module module;
if (OSDynLoad_Acquire("homebrew_memorymapping", &module) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE("Failed to acquire homebrew_memorymapping.");
return {};
}
/* Memory allocation functions */
uint32_t *allocPtr = nullptr, *freePtr = nullptr;
if (OSDynLoad_FindExport(module, OS_DYNLOAD_EXPORT_DATA, "MEMAllocFromMappedMemoryEx", reinterpret_cast<void **>(&allocPtr)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport for MEMAllocFromDefaultHeapEx failed");
return {};
}
if (OSDynLoad_FindExport(module, OS_DYNLOAD_EXPORT_DATA, "MEMFreeToMappedMemory", reinterpret_cast<void **>(&freePtr)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport for MEMFreeToDefaultHeap failed");
return {};
}
MEMAllocFromDefaultHeapExForThreads = (void *(*) (uint32_t, int) ) * allocPtr;
MEMFreeToDefaultHeapForThreads = (void (*)(void *)) * freePtr;
if (!MEMAllocFromDefaultHeapExForThreads || !MEMFreeToDefaultHeapForThreads) {
DEBUG_FUNCTION_LINE_ERR("MEMAllocFromDefaultHeapExForThreads or MEMFreeToDefaultHeapForThreads is null");
// the mapped memory is not available (yet)
return {};
}
uint32_t size = heapSize;
auto ptr = MEMAllocFromDefaultHeapExForThreads(size, 0x4);
if (!ptr) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory: %d bytes", size);
return {};
}
DEBUG_FUNCTION_LINE("Let's create a memory wrapper for 0x%08X, size: %d", ptr, size);
return HeapWrapper(MemoryWrapper(ptr, size, MEMFreeToDefaultHeapForThreads));
}
std::optional<HeapWrapper> GetHeapForModule(uint32_t heapSize) {
// If Aroma is already loaded, we can't use the region between MEMORY_REGION_START and MEMORY_REGION_END anymore because Aroma is using.
// So instead we check before loading a module if aromas memory mapping module is already usable. If yes, we use this to load the module instead
if (auto heapWrapper = GetHeapFromMappedMemory(heapSize)) {
return heapWrapper;
}
// If Aroma is not already loaded, we use the existing 0x00800000 - 0x01000000 memory region. This is where aroma is loaded to. Note: this region may be only mapped to the main core.
// The environment loader is loaded to the end of 0x00800000 - 0x01000000 memory region. With this helper we know the start of the .text section
uint32_t textSectionStart = textStart() - 0x100;
auto endOfUsableMemory = textSectionStart;
uint32_t startAddress = ((uint32_t) endOfUsableMemory - heapSize) & 0xFFFF0000;
uint32_t size = endOfUsableMemory - startAddress;
if (startAddress < MEMORY_REGION_START) {
DEBUG_FUNCTION_LINE_ERR("Not enough static memory");
return {};
}
DEBUG_FUNCTION_LINE("Let's create a memory wrapper for 0x%08X, size: %d", startAddress, size);
auto res = HeapWrapper(MemoryWrapper((void *) startAddress, size, /* we don't need to free this memory*/ nullptr));
if ((uint32_t) res.GetHeapHandle() != startAddress) {
OSFatal("EnvironmentLoader: Unexpected address");
}
return res;
}
void SetupKernelModule() {
void *(*KernelSetupDefaultSyscalls)() = nullptr;
OSDynLoad_Module module;
if (OSDynLoad_Acquire("homebrew_kernel", &module) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE("Failed to acquire homebrew_kernel.");
return;
}
if (OSDynLoad_FindExport(module, OS_DYNLOAD_EXPORT_FUNC, "KernelSetupDefaultSyscalls", reinterpret_cast<void **>(&KernelSetupDefaultSyscalls)) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport for KernelSetupDefaultSyscalls failed");
OSFatal("EnvironmentLoader: KernelModule is missing the export\n"
"\"KernelSetupDefaultSyscalls\"... Please update Aroma!\n"
"\n"
"See https://wiiu.hacks.guide/ for more information.");
return;
}
if (!KernelSetupDefaultSyscalls) {
DEBUG_FUNCTION_LINE_WARN("KernelSetupDefaultSyscalls is null");
OSFatal("EnvironmentLoader: KernelModule is missing the export\n"
"\"KernelSetupDefaultSyscalls\"... Please update Aroma!\n"
"\n"
"See https://wiiu.hacks.guide/ for more information.");
return;
}
DEBUG_FUNCTION_LINE("Call KernelSetupDefaultSyscalls");
KernelSetupDefaultSyscalls();
OSDynLoad_Release(module);
}
void LoadAndRunModule(std::string_view filepath, std::string_view environment_path) {
// Some module may unmount the sd card on exit.
FSAInit();
auto client = FSAAddClient(nullptr);
if (client) {
FSAMount(client, "/dev/sdcard01", "/vol/external01", static_cast<FSAMountFlags>(0), nullptr, 0);
FSADelClient(client);
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to add FSA client");
}
DEBUG_FUNCTION_LINE("Trying to load %s into memory", filepath.data());
uint8_t *buffer = nullptr;
uint32_t fsize = 0;
if (LoadFileToMem(filepath.data(), &buffer, &fsize) < 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to load file");
OSFatal("EnvironmentLoader: Failed to load file to memory");
return;
}
auto cleanupBuffer = onLeavingScope([buffer]() { free(buffer); });
ELFIO::elfio reader(new wiiu_zlib);
// Load ELF data
if (!reader.load(reinterpret_cast<const char *>(buffer), fsize)) {
DEBUG_FUNCTION_LINE_ERR("Can't parse .wms from buffer.");
OSFatal("Can't parse .wms from buffer.");
return;
}
uint32_t moduleSize = ModuleDataFactory::GetSizeOfModule(reader);
DEBUG_FUNCTION_LINE_VERBOSE("Module has size: %d", moduleSize);
uint32_t requiredHeapSize = moduleSize + sizeof(module_information_t) + 0x10000; // add another 0x10000 to be safe
DEBUG_FUNCTION_LINE_VERBOSE("Allocate %d bytes for heap (%.2f KiB)", requiredHeapSize, requiredHeapSize / 1024.0f);
if (auto heapWrapperOpt = GetHeapForModule(requiredHeapSize); heapWrapperOpt.has_value()) {
// Frees automatically, must not survive the heapWrapper.
auto moduleInfoOpt = heapWrapperOpt->Alloc(sizeof(module_information_t), 0x4);
if (!moduleInfoOpt) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc module information");
OSFatal("EnvironmentLoader: Failed to alloc module information");
return;
}
auto moduleInfo = std::move(*moduleInfoOpt);
auto moduleInfoPtr = (module_information_t *) moduleInfo.data();
*moduleInfoPtr = {};
// Frees automatically, must not survive the heapWrapper.
auto moduleData = ModuleDataFactory::load(reader, *heapWrapperOpt, moduleInfoPtr->trampolines, sizeof(moduleInfoPtr->trampolines) / sizeof(moduleInfoPtr->trampolines[0]));
if (!moduleData) {
DEBUG_FUNCTION_LINE_ERR("Failed to load %s", filepath);
OSFatal("EnvironmentLoader: Failed to load module");
return;
}
DEBUG_FUNCTION_LINE("Loaded module data");
std::map<std::string, OSDynLoad_Module> usedRPls;
if (!ElfUtils::doRelocation(moduleData.value()->getRelocationDataList(), moduleInfoPtr->trampolines, sizeof(moduleInfoPtr->trampolines) / sizeof(moduleInfoPtr->trampolines[0]), usedRPls)) {
DEBUG_FUNCTION_LINE_ERR("Relocations failed");
OSFatal("EnvironmentLoader: Relocations failed");
} else {
DEBUG_FUNCTION_LINE("Relocation done");
}
char *arr[4];
arr[0] = (char *) environment_path.data();
arr[1] = (char *) "EnvironmentLoader"; //
arr[2] = (char *) 0x02; // Version
/*
* This is a hacky work around to tell Aromas Module Loader which memory region it can use safely. After using it, it's expected to expose new memory region via the
* custom rpl "homebrew_mappedmemory" (See: GetHeapFromMappedMemory). The returned memory is expected to be RWX for user and kernel.
* Once a custom memory allocator is provided, usable_mem_start and usable_mem_end are set to 0.
*/
auto usable_mem_end = (uint32_t) heapWrapperOpt->GetHeapHandle();
if (heapWrapperOpt->IsAllocated()) { // Check if you use memory which is actually allocated. This means we can't give it to the module.
DEBUG_FUNCTION_LINE("Don't give the module a usable memory region because it will be loaded on a custom memory region.");
usable_mem_end = 0;
}
arr[3] = (char *) usable_mem_end; // End of usable memory
DEBUG_FUNCTION_LINE("Calling entrypoint @%08X with: \"%s\", \"%s\", %08X, %08X", moduleData.value()->getEntrypoint(), arr[0], arr[1], arr[2], arr[3]);
// clang-format off
((int(*)(int, char **)) moduleData.value()->getEntrypoint())(sizeof(arr)/ sizeof(arr[0]), arr);
// clang-format on
DEBUG_FUNCTION_LINE("Back from module");
for (auto &rpl : usedRPls) {
DEBUG_FUNCTION_LINE_VERBOSE("Release %s", rpl.first.c_str());
OSDynLoad_Release(rpl.second);
}
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to create heap");
OSFatal("EnvironmentLoader: Failed to create heap");
}
// module may override the syscalls used by the Aroma KernelModule. This (tries to) re-init(s) the KernelModule after a setup module has been run.
SetupKernelModule();
}
void ClearSavedFrameBuffers() {
// If GX2 is running make sure to shut it down and free all existing memory in the saved-frame area.
if (GX2GetMainCoreId() != -1) {
GX2SetTVEnable(FALSE);
GX2SetDRCEnable(FALSE);
GX2Shutdown();
}
__OSClearSavedFrame(OS_SAVED_FRAME_A, OS_SAVED_FRAME_SCREEN_TV);
__OSClearSavedFrame(OS_SAVED_FRAME_A, OS_SAVED_FRAME_SCREEN_DRC);
__OSClearSavedFrame(OS_SAVED_FRAME_B, OS_SAVED_FRAME_SCREEN_TV);
__OSClearSavedFrame(OS_SAVED_FRAME_B, OS_SAVED_FRAME_SCREEN_DRC);
}
void AbortQuickStartMenu() {
CCRCDCDrcState state = {};
CCRCDCSysGetDrcState(CCR_CDC_DESTINATION_DRC0, &state);
if (state.state == CCR_CDC_DRC_STATE_SUBACTIVE) {
state.state = CCR_CDC_DRC_STATE_ACTIVE;
CCRCDCSysSetDrcState(CCR_CDC_DESTINATION_DRC0, &state);
}
}
std::string EnvironmentSelectionScreen(const std::map<std::string, std::string> &payloads, int32_t autobootIndex) {
// Close quick start menu is selection screen is displayed
AbortQuickStartMenu();
// Clear saved frame buffer to reduce screen corruption
ClearSavedFrameBuffers();
OSScreenInit();
uint32_t tvBufferSize = OSScreenGetBufferSizeEx(SCREEN_TV);
@ -276,7 +479,7 @@ std::string EnvironmentSelectionScreen(const std::map<std::string, std::string>
auto *screenBuffer = (uint8_t *) memalign(0x100, tvBufferSize + drcBufferSize);
if (!screenBuffer) {
OSFatal("Fail to allocate screenBuffer");
OSFatal("EnvironmentLoader: Fail to allocate screenBuffer");
}
memset(screenBuffer, 0, tvBufferSize + drcBufferSize);
@ -287,37 +490,40 @@ std::string EnvironmentSelectionScreen(const std::map<std::string, std::string>
OSScreenEnableEx(SCREEN_DRC, TRUE);
DrawUtils::initBuffers(screenBuffer, tvBufferSize, screenBuffer + tvBufferSize, drcBufferSize);
DrawUtils::initFont();
if (!DrawUtils::initFont()) {
OSFatal("EnvironmentLoader: Failed to init font");
}
uint32_t selected = autobootIndex > 0 ? autobootIndex : 0;
int autoBoot = autobootIndex;
bool redraw = true;
while (true) {
VPADStatus vpad{};
VPADRead(VPAD_CHAN_0, &vpad, 1, nullptr);
if (vpad.trigger & VPAD_BUTTON_UP) {
if (selected > 0) {
selected--;
redraw = true;
{
PairMenu pairMenu;
while (true) {
if (pairMenu.ProcessPairScreen()) {
continue;
}
} else if (vpad.trigger & VPAD_BUTTON_DOWN) {
if (selected < payloads.size() - 1) {
selected++;
redraw = true;
}
} else if (vpad.trigger & VPAD_BUTTON_A) {
break;
} else if (vpad.trigger & VPAD_BUTTON_X) {
autoBoot = -1;
redraw = true;
} else if (vpad.trigger & VPAD_BUTTON_Y) {
autoBoot = selected;
redraw = true;
}
if (redraw) {
InputUtils::InputData input = InputUtils::getControllerInput();
if (input.trigger & VPAD_BUTTON_UP) {
if (selected > 0) {
selected--;
}
} else if (input.trigger & VPAD_BUTTON_DOWN) {
if (selected < payloads.size() - 1) {
selected++;
}
} else if (input.trigger & VPAD_BUTTON_A) {
break;
} else if (input.trigger & (VPAD_BUTTON_X | VPAD_BUTTON_MINUS)) {
autoBoot = -1;
} else if (input.trigger & (VPAD_BUTTON_Y | VPAD_BUTTON_PLUS)) {
autoBoot = selected;
}
DrawUtils::beginDraw();
DrawUtils::clear(COLOR_BACKGROUND);
@ -351,6 +557,8 @@ std::string EnvironmentSelectionScreen(const std::map<std::string, std::string>
DrawUtils::setFontSize(24);
DrawUtils::print(16, 6 + 24, "Environment Loader");
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
DrawUtils::setFontSize(16);
DrawUtils::print(SCREEN_WIDTH - 16, 6 + 24, ENVIRONMENT_LOADER_VERSION ENVIRONMENT_LOADER_VERSION_EXTRA, true);
// draw bottom bar
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
@ -358,15 +566,13 @@ std::string EnvironmentSelectionScreen(const std::map<std::string, std::string>
if (!payloads.empty()) {
DrawUtils::print(16, SCREEN_HEIGHT - 8, "\ue07d Navigate ");
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue000 Choose", true);
const char *autobootHints = "\ue002 Clear Default / \ue003 Select Default";
const char *autobootHints = "\ue002/\ue046 Clear Default / \ue003/\ue045 Select Default";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(autobootHints) / 2, SCREEN_HEIGHT - 8, autobootHints, true);
} else {
DrawUtils::print(SCREEN_WIDTH - 20, SCREEN_HEIGHT - 8, "\ue000 Wii U Menu", true);
}
DrawUtils::endDraw();
redraw = false;
}
}
@ -379,6 +585,9 @@ std::string EnvironmentSelectionScreen(const std::map<std::string, std::string>
// Call GX2Init to shut down OSScreen
GX2Init(nullptr);
GX2SetTVEnable(FALSE);
GX2SetDRCEnable(FALSE);
free(screenBuffer);
if (autoBoot != autobootIndex) {

View File

@ -39,7 +39,7 @@ public:
[[nodiscard]] const char *getRPLName() const {
if (name.max_size() < strlen("._import_") + 1) {
OSFatal("Invalid RPLName, is too short to be valid");
OSFatal("EnvironmentLoader: Invalid RPLName, is too short to be valid");
}
return name.c_str() + strlen("._import_");
}

View File

@ -18,6 +18,7 @@
#pragma once
#include "RelocationData.h"
#include "utils/MemoryUtils.h"
#include <map>
#include <set>
#include <string>
@ -33,11 +34,11 @@ public:
this->entrypoint = address;
}
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
void addRelocationData(RelocationData relocation_data) {
relocation_data_list.push_back(std::move(relocation_data));
}
[[nodiscard]] const std::vector<std::unique_ptr<RelocationData>> &getRelocationDataList() const {
[[nodiscard]] const std::vector<RelocationData> &getRelocationDataList() const {
return relocation_data_list;
}
@ -45,25 +46,16 @@ public:
return entrypoint;
}
void setStartAddress(uint32_t address) {
this->startAddress = address;
void setTextMemory(ExpHeapMemory &&memory) {
mTextMemory = std::move(memory);
}
void setEndAddress(uint32_t address) {
this->endAddress = address;
}
[[nodiscard]] uint32_t getStartAddress() const {
return startAddress;
}
[[nodiscard]] uint32_t getEndAddress() const {
return endAddress;
void setDataMemory(ExpHeapMemory &&memory) {
mDataMemory = std::move(memory);
}
private:
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
uint32_t entrypoint = 0;
uint32_t startAddress = 0;
uint32_t endAddress = 0;
std::vector<RelocationData> relocation_data_list;
uint32_t entrypoint = 0;
ExpHeapMemory mTextMemory;
ExpHeapMemory mDataMemory;
};

View File

@ -20,36 +20,36 @@
#include "ElfUtils.h"
#include "utils/OnLeavingScope.h"
#include "utils/utils.h"
#include "utils/wiiu_zlib.hpp"
#include <coreinit/cache.h>
#include <map>
#include <string>
#include <vector>
uint32_t ModuleDataFactory::GetSizeOfModule(const ELFIO::elfio &reader) {
uint32_t sec_num = reader.sections.size();
uint32_t sizeOfModule = 0;
for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
if (psec->get_type() == 0x80000002 || psec->get_name() == ".wut_load_bounds") {
continue;
}
if ((psec->get_type() == ELFIO::SHT_PROGBITS || psec->get_type() == ELFIO::SHT_NOBITS) && (psec->get_flags() & ELFIO::SHF_ALLOC)) {
sizeOfModule += psec->get_size() + psec->get_addr_align();
}
}
return sizeOfModule;
}
std::optional<std::unique_ptr<ModuleData>>
ModuleDataFactory::load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
ELFIO::elfio reader;
ModuleDataFactory::load(const ELFIO::elfio &reader, const HeapWrapper &heapWrapper, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
auto moduleData = make_unique_nothrow<ModuleData>();
if (!moduleData) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate ModuleData");
return {};
}
uint8_t *buffer = nullptr;
uint32_t fsize = 0;
if (LoadFileToMem(path.c_str(), &buffer, &fsize) < 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to load file");
return {};
}
// Load ELF data
if (!reader.load(reinterpret_cast<char *>(buffer), fsize)) {
DEBUG_FUNCTION_LINE_ERR("Can't find or process %s", path.c_str());
free(buffer);
return {};
}
auto cleanupBuffer = onLeavingScope([buffer]() { free(buffer); });
uint32_t sec_num = reader.sections.size();
auto destinations = make_unique_nothrow<uint8_t *[]>(sec_num);
@ -58,33 +58,41 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
return {};
}
uint32_t sizeOfModule = 0;
uint32_t text_size = 0;
uint32_t data_size = 0;
for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
if (psec->get_type() == 0x80000002) {
continue;
}
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
sizeOfModule += psec->get_size() + 1;
if ((psec->get_type() == ELFIO::SHT_PROGBITS || psec->get_type() == ELFIO::SHT_NOBITS) && (psec->get_flags() & ELFIO::SHF_ALLOC)) {
uint32_t sectionSize = psec->get_size();
auto address = (uint32_t) psec->get_address();
if ((address >= 0x02000000) && address < 0x10000000) {
text_size += sectionSize + psec->get_addr_align();
} else if ((address >= 0x10000000) && address < 0xC0000000) {
data_size += sectionSize + psec->get_addr_align();
}
}
}
if (sizeOfModule > maximum_size) {
DEBUG_FUNCTION_LINE_ERR("Module is too big.");
return {};
auto text_dataOpt = heapWrapper.Alloc(text_size, 0x100);
if (!text_dataOpt) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
return std::nullopt;
}
ExpHeapMemory text_data = std::move(*text_dataOpt);
uint32_t baseOffset = (destination_address_end - sizeOfModule) & 0xFFFFFF00;
uint32_t startAddress = baseOffset;
auto data_dataOpt = heapWrapper.Alloc(data_size, 0x100);
if (!data_dataOpt) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size);
return std::nullopt;
}
ExpHeapMemory data_data = std::move(*data_dataOpt);
uint32_t offset_text = baseOffset;
uint32_t offset_data = offset_text;
uint32_t entrypoint = offset_text + (uint32_t) reader.get_entry() - 0x02000000;
uint32_t totalSize = 0;
uint32_t endAddress = 0;
uint32_t entrypoint = (uint32_t) text_data.data() + (uint32_t) reader.get_entry() - 0x02000000;
for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
@ -92,28 +100,36 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
continue;
}
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
if ((psec->get_type() == ELFIO::SHT_PROGBITS || psec->get_type() == ELFIO::SHT_NOBITS) && (psec->get_flags() & ELFIO::SHF_ALLOC)) {
uint32_t sectionSize = psec->get_size();
auto address = (uint32_t) psec->get_address();
totalSize += sectionSize;
if (totalSize > maximum_size) {
DEBUG_FUNCTION_LINE_ERR("Couldn't load setup module because it's too big.");
return {};
}
uint32_t destination = address;
auto address = (uint32_t) psec->get_address();
destinations[psec->get_index()] = (uint8_t *) baseOffset;
uint32_t destination = baseOffset + address;
if ((address >= 0x02000000) && address < 0x10000000) {
destination += (uint32_t) text_data.data();
destination -= 0x02000000;
destinations[psec->get_index()] -= 0x02000000;
baseOffset += sectionSize;
offset_data += sectionSize;
destinations[psec->get_index()] = (uint8_t *) text_data.data();
if (destination + sectionSize > (uint32_t) text_data.data() + text_size) {
DEBUG_FUNCTION_LINE_ERR("Tried to overflow .text buffer. %08X > %08X", destination + sectionSize, (uint32_t) text_data.data() + text_data.size());
OSFatal("EnvironmentLoader: Tried to overflow .text buffer");
} else if (destination < (uint32_t) text_data.data()) {
DEBUG_FUNCTION_LINE_ERR("Tried to underflow .text buffer. %08X < %08X", destination, (uint32_t) text_data.data());
OSFatal("EnvironmentLoader: Tried to underflow .text buffer");
}
} else if ((address >= 0x10000000) && address < 0xC0000000) {
destination += (uint32_t) data_data.data();
destination -= 0x10000000;
destinations[psec->get_index()] -= 0x10000000;
destinations[psec->get_index()] = (uint8_t *) data_data.data();
if (destination + sectionSize > (uint32_t) data_data.data() + data_data.size()) {
DEBUG_FUNCTION_LINE_ERR("Tried to overflow .data buffer. %08X > %08X", destination + sectionSize, (uint32_t) data_data.data() + data_data.size());
OSFatal("EnvironmentLoader: Tried to overflow .data buffer");
} else if (destination < (uint32_t) data_data.data()) {
DEBUG_FUNCTION_LINE_ERR("Tried to underflow .data buffer. %08X < %08X", destination, (uint32_t) data_data.data());
OSFatal("EnvironmentLoader: Tried to underflow .data buffer");
}
} else if (address >= 0xC0000000) {
DEBUG_FUNCTION_LINE_ERR("Loading section from 0xC0000000 is NOT supported");
return std::nullopt;
@ -122,30 +138,22 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
return std::nullopt;
}
const char *p = reader.sections[i]->get_data();
const char *p = psec->get_data();
if (destination + sectionSize > (uint32_t) destination_address_end) {
DEBUG_FUNCTION_LINE_ERR("Tried to overflow buffer. %08X > %08X", destination + sectionSize, destination_address_end);
OSFatal("EnvironmentLoader: Tried to overflow buffer");
uint32_t address_align = psec->get_addr_align();
if ((destination & (address_align - 1)) != 0) {
DEBUG_FUNCTION_LINE_WARN("Address not aligned: %08X %08X", destination, address_align);
OSFatal("EnvironmentLoader: Address not aligned");
}
if (psec->get_type() == SHT_NOBITS) {
DEBUG_FUNCTION_LINE("memset section %s %08X to 0 (%d bytes)", psec->get_name().c_str(), destination, sectionSize);
if (psec->get_type() == ELFIO::SHT_NOBITS) {
DEBUG_FUNCTION_LINE_VERBOSE("memset section %s %08X to 0 (%d bytes)", psec->get_name().c_str(), destination, sectionSize);
memset((void *) destination, 0, sectionSize);
} else if (psec->get_type() == SHT_PROGBITS) {
DEBUG_FUNCTION_LINE("Copy section %s %08X -> %08X (%d bytes)", psec->get_name().c_str(), p, destination, sectionSize);
} else if (psec->get_type() == ELFIO::SHT_PROGBITS) {
DEBUG_FUNCTION_LINE_VERBOSE("Copy section %s %08X -> %08X (%d bytes)", psec->get_name().c_str(), p, destination, sectionSize);
memcpy((void *) destination, p, sectionSize);
}
//nextAddress = ROUNDUP(destination + sectionSize, 0x100);
if (psec->get_name() == ".bss" || psec->get_name() == ".sbss") {
DEBUG_FUNCTION_LINE("memset %s section. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
}
if (endAddress < destination + sectionSize) {
endAddress = destination + sectionSize;
}
DEBUG_FUNCTION_LINE_VERBOSE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
DCFlushRange((void *) destination, sectionSize);
ICInvalidateRange((void *) destination, sectionSize);
@ -154,9 +162,9 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
if ((psec->get_type() == ELFIO::SHT_PROGBITS || psec->get_type() == ELFIO::SHT_NOBITS) && (psec->get_flags() & ELFIO::SHF_ALLOC)) {
DEBUG_FUNCTION_LINE("Linking (%d)... %s", i, psec->get_name().c_str());
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampoline_data, trampoline_data_length)) {
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) (text_data.data()), (uint32_t) (data_data.data()), trampoline_data, trampoline_data_length)) {
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
return std::nullopt;
}
@ -164,18 +172,19 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
}
getImportRelocationData(moduleData, reader, destinations.get());
DCFlushRange((void *) baseOffset, totalSize);
ICInvalidateRange((void *) baseOffset, totalSize);
DCFlushRange((void *) data_data.data(), data_data.size());
ICInvalidateRange((void *) text_data.data(), text_data.size());
moduleData->setStartAddress(startAddress);
moduleData->setEndAddress(endAddress);
moduleData->setEntrypoint(entrypoint);
moduleData->setTextMemory(std::move(text_data));
moduleData->setDataMemory(std::move(data_data));
DEBUG_FUNCTION_LINE("Saved entrypoint as %08X", entrypoint);
return moduleData;
}
bool ModuleDataFactory::getImportRelocationData(std::unique_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations) {
bool ModuleDataFactory::getImportRelocationData(std::unique_ptr<ModuleData> &moduleData, const ELFIO::elfio &reader, uint8_t **destinations) {
std::map<uint32_t, std::shared_ptr<ImportRPLInformation>> infoMap;
uint32_t sec_num = reader.sections.size();
@ -194,20 +203,34 @@ bool ModuleDataFactory::getImportRelocationData(std::unique_ptr<ModuleData> &mod
for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) {
if (psec->get_type() == ELFIO::SHT_RELA || psec->get_type() == ELFIO::SHT_REL) {
DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str());
ELFIO::relocation_section_accessor rel(reader, psec);
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
ELFIO::Elf_Word symbol = 0;
ELFIO::Elf64_Addr offset;
ELFIO::Elf_Word type;
ELFIO::Elf_Sxword addend;
std::string sym_name;
ELFIO::Elf64_Addr sym_value;
ELFIO::Elf_Half sym_section_index;
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
if (!rel.get_entry(j, offset, symbol, type, addend)) {
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
OSFatal("Failed to get relocation");
break;
return false;
}
ELFIO::symbol_section_accessor symbols(reader, reader.sections[(ELFIO::Elf_Half) psec->get_link()]);
// Find the symbol
ELFIO::Elf_Xword size;
unsigned char bind;
unsigned char symbolType;
ELFIO::Elf_Half sym_section_index;
unsigned char other;
if (!symbols.get_symbol(symbol, sym_name, sym_value, size,
bind, symbolType, sym_section_index, other)) {
DEBUG_FUNCTION_LINE_ERR("Failed to get symbol");
return false;
}
auto adjusted_sym_value = (uint32_t) sym_value;
@ -218,29 +241,23 @@ bool ModuleDataFactory::getImportRelocationData(std::unique_ptr<ModuleData> &mod
uint32_t section_index = psec->get_info();
if (!infoMap.contains(sym_section_index)) {
DEBUG_FUNCTION_LINE_ERR("Relocation is referencing a unknown section. %d destination: %08X sym_name %s", section_index, destinations[section_index], sym_name.c_str());
OSFatal("Relocation is referencing a unknown section.");
}
auto relocationData = make_unique_nothrow<RelocationData>(type,
offset - 0x02000000,
addend,
(void *) (destinations[section_index] + 0x02000000),
sym_name,
infoMap[sym_section_index]);
if (!relocationData) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc relocation data");
OSFatal("EnvironmentLoader: Relocation is referencing a unknown section.");
return false;
}
moduleData->addRelocationData(std::move(relocationData));
moduleData->addRelocationData(RelocationData(type,
offset - 0x02000000,
addend,
(void *) (destinations[section_index]),
sym_name,
infoMap[sym_section_index]));
}
}
}
return true;
}
bool ModuleDataFactory::linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
bool ModuleDataFactory::linkSection(const ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
uint32_t trampoline_data_length) {
uint32_t sec_num = reader.sections.size();
@ -250,17 +267,31 @@ bool ModuleDataFactory::linkSection(ELFIO::elfio &reader, uint32_t section_index
DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str());
ELFIO::relocation_section_accessor rel(reader, psec);
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
ELFIO::Elf_Word symbol = 0;
ELFIO::Elf64_Addr offset;
ELFIO::Elf_Word type;
ELFIO::Elf_Sxword addend;
std::string sym_name;
ELFIO::Elf64_Addr sym_value;
ELFIO::Elf_Half sym_section_index;
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
if (!rel.get_entry(j, offset, symbol, type, addend)) {
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
return false;
}
ELFIO::symbol_section_accessor symbols(reader, reader.sections[(ELFIO::Elf_Half) psec->get_link()]);
// Find the symbol
ELFIO::Elf_Xword size;
unsigned char bind;
unsigned char symbolType;
ELFIO::Elf_Half sym_section_index;
unsigned char other;
if (!symbols.get_symbol(symbol, sym_name, sym_value, size,
bind, symbolType, sym_section_index, other)) {
DEBUG_FUNCTION_LINE_ERR("Failed to get symbol");
return false;
}
auto adjusted_sym_value = (uint32_t) sym_value;
if ((adjusted_sym_value >= 0x02000000) && adjusted_sym_value < 0x10000000) {
@ -279,17 +310,27 @@ bool ModuleDataFactory::linkSection(ELFIO::elfio &reader, uint32_t section_index
return false;
}
if (sym_section_index == SHN_ABS) {
auto adjusted_offset = (uint32_t) offset;
if ((offset >= 0x02000000) && offset < 0x10000000) {
adjusted_offset -= 0x02000000;
} else if ((adjusted_offset >= 0x10000000) && adjusted_offset < 0xC0000000) {
adjusted_offset -= 0x10000000;
} else if (adjusted_offset >= 0xC0000000) {
adjusted_offset -= 0xC0000000;
}
if (sym_section_index == ELFIO::SHN_ABS) {
//
} else if (sym_section_index > SHN_LORESERVE) {
} else if (sym_section_index > ELFIO::SHN_LORESERVE) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED: %04X", sym_section_index);
return false;
}
if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
if (!ElfUtils::elfLinkOne(type, adjusted_offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
DEBUG_FUNCTION_LINE_ERR("Link failed");
return false;
}
}
return true;
}
}
return true;

View File

@ -20,17 +20,20 @@
#include "../common/relocation_defines.h"
#include "ModuleData.h"
#include "elfio/elfio.hpp"
#include "utils/MemoryUtils.h"
#include "utils/utils.h"
#include <map>
#include <string>
#include <vector>
class ModuleDataFactory {
public:
static std::optional<std::unique_ptr<ModuleData>>
load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length);
static uint32_t GetSizeOfModule(const ELFIO::elfio &reader);
static bool linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
static std::optional<std::unique_ptr<ModuleData>> load(const ELFIO::elfio &reader, const HeapWrapper &heapWrapper, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length);
static bool linkSection(const ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
uint32_t trampoline_data_length);
static bool getImportRelocationData(std::unique_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations);
static bool getImportRelocationData(std::unique_ptr<ModuleData> &moduleData, const ELFIO::elfio &reader, uint8_t **destinations);
};

View File

@ -1,12 +1,13 @@
#include "DrawUtils.h"
#include <cmath>
#include "logger.h"
#include "utils.h"
#include <coreinit/cache.h>
#include <coreinit/memory.h>
#include <coreinit/screen.h>
#include <ft2build.h>
#include <cstdlib>
#include <png.h>
#include FT_FREETYPE_H
// buffer width
#define TV_WIDTH 0x500
@ -18,17 +19,15 @@ uint8_t *DrawUtils::tvBuffer = nullptr;
uint32_t DrawUtils::tvSize = 0;
uint8_t *DrawUtils::drcBuffer = nullptr;
uint32_t DrawUtils::drcSize = 0;
static SFT pFont = {};
// Don't put those into the class or we have to include ft everywhere
static FT_Library ft_lib = nullptr;
static FT_Face ft_face = nullptr;
static Color font_col = {0xFFFFFFFF};
static Color font_col(0xFFFFFFFF);
void DrawUtils::initBuffers(void *tvBuffer, uint32_t tvSize, void *drcBuffer, uint32_t drcSize) {
DrawUtils::tvBuffer = (uint8_t *) tvBuffer;
DrawUtils::tvSize = tvSize;
DrawUtils::drcBuffer = (uint8_t *) drcBuffer;
DrawUtils::drcSize = drcSize;
void DrawUtils::initBuffers(void *tvBuffer_, uint32_t tvSize_, void *drcBuffer_, uint32_t drcSize_) {
DrawUtils::tvBuffer = (uint8_t *) tvBuffer_;
DrawUtils::tvSize = tvSize_;
DrawUtils::drcBuffer = (uint8_t *) drcBuffer_;
DrawUtils::drcSize = drcSize_;
}
void DrawUtils::beginDraw() {
@ -80,10 +79,17 @@ void DrawUtils::drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t
}
}
uint32_t USED_TV_WIDTH = TV_WIDTH;
float scale = 1.5f;
if (DrawUtils::tvSize == 0x00FD2000) {
USED_TV_WIDTH = 1920;
scale = 2.25f;
}
// scale and put pixel in the tv buffer
for (uint32_t yy = (y * 1.5); yy < ((y * 1.5) + 1); yy++) {
for (uint32_t xx = (x * 1.5); xx < ((x * 1.5) + 1); xx++) {
uint32_t i = (xx + yy * TV_WIDTH) * 4;
for (uint32_t yy = (y * scale); yy < ((y * scale) + (uint32_t) scale); yy++) {
for (uint32_t xx = (x * scale); xx < ((x * scale) + (uint32_t) scale); xx++) {
uint32_t i = (xx + yy * USED_TV_WIDTH) * 4;
if (i + 3 < tvSize / 2) {
if (isBackBuffer) {
i += tvSize / 2;
@ -151,14 +157,14 @@ static void png_read_data(png_structp png_ptr, png_bytep outBytes, png_size_t by
}
void DrawUtils::drawPNG(uint32_t x, uint32_t y, const uint8_t *data) {
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (png_ptr == nullptr) {
return;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
if (info_ptr == nullptr) {
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
return;
}
@ -170,16 +176,16 @@ void DrawUtils::drawPNG(uint32_t x, uint32_t y, const uint8_t *data) {
uint32_t height = 0;
int bitDepth = 0;
int colorType = -1;
uint32_t retval = png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL);
uint32_t retval = png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, nullptr, nullptr, nullptr);
if (retval != 1) {
return;
}
uint32_t bytesPerRow = png_get_rowbytes(png_ptr, info_ptr);
uint8_t *rowData = new uint8_t[bytesPerRow];
auto *rowData = new uint8_t[bytesPerRow];
for (uint32_t yy = y; yy < y + height; yy++) {
png_read_row(png_ptr, (png_bytep) rowData, NULL);
png_read_row(png_ptr, (png_bytep) rowData, nullptr);
for (uint32_t xx = x; xx < x + width; xx++) {
if (colorType == PNG_COLOR_TYPE_RGB_ALPHA) {
@ -193,37 +199,52 @@ void DrawUtils::drawPNG(uint32_t x, uint32_t y, const uint8_t *data) {
}
delete[] rowData;
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
}
void DrawUtils::initFont() {
void *font = NULL;
bool DrawUtils::initFont() {
void *font = nullptr;
uint32_t size = 0;
OSGetSharedData(OS_SHAREDDATATYPE_FONT_STANDARD, 0, &font, &size);
if (font && size) {
FT_Init_FreeType(&ft_lib);
FT_New_Memory_Face(ft_lib, (FT_Byte *) font, size, 0, &ft_face);
pFont.xScale = 20;
pFont.yScale = 20,
pFont.flags = SFT_DOWNWARD_Y;
pFont.font = sft_loadmem(font, size);
if (!pFont.font) {
return false;
}
OSMemoryBarrier();
return true;
}
return false;
}
void DrawUtils::deinitFont() {
FT_Done_Face(ft_face);
FT_Done_FreeType(ft_lib);
sft_freefont(pFont.font);
pFont.font = nullptr;
pFont = {};
}
void DrawUtils::setFontSize(uint32_t size) {
FT_Set_Pixel_Sizes(ft_face, 0, size);
pFont.xScale = size;
pFont.yScale = size;
SFT_LMetrics metrics;
sft_lmetrics(&pFont, &metrics);
}
void DrawUtils::setFontColor(Color col) {
font_col = col;
}
static void draw_freetype_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y) {
FT_Int i, j, p, q;
FT_Int x_max = x + bitmap->width;
FT_Int y_max = y + bitmap->rows;
static void draw_freetype_bitmap(SFT_Image *bmp, int32_t x, int32_t y) {
int32_t i, j, p, q;
int32_t x_max = x + bmp->width;
int32_t y_max = y + bmp->height;
auto *src = (uint8_t *) bmp->pixels;
for (i = x, p = 0; i < x_max; i++, p++) {
for (j = y, q = 0; j < y_max; j++, q++) {
@ -231,14 +252,14 @@ static void draw_freetype_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y) {
continue;
}
float opacity = bitmap->buffer[q * bitmap->pitch + p] / 255.0f;
float opacity = src[q * bmp->width + p] / 255.0f;
DrawUtils::drawPixel(i, j, font_col.r, font_col.g, font_col.b, font_col.a * opacity);
}
}
}
void DrawUtils::print(uint32_t x, uint32_t y, const char *string, bool alignRight) {
wchar_t *buffer = new wchar_t[strlen(string) + 1];
auto *buffer = new wchar_t[strlen(string) + 1];
size_t num = mbstowcs(buffer, string, strlen(string));
if (num > 0) {
@ -254,32 +275,64 @@ void DrawUtils::print(uint32_t x, uint32_t y, const char *string, bool alignRigh
}
void DrawUtils::print(uint32_t x, uint32_t y, const wchar_t *string, bool alignRight) {
FT_GlyphSlot slot = ft_face->glyph;
FT_Vector pen = {(int) x, (int) y};
auto penX = (int32_t) x;
auto penY = (int32_t) y;
if (alignRight) {
pen.x -= getTextWidth(string);
penX -= getTextWidth(string);
}
uint16_t textureWidth = 0, textureHeight = 0;
for (; *string; string++) {
uint32_t charcode = *string;
SFT_Glyph gid; // unsigned long gid;
if (sft_lookup(&pFont, *string, &gid) >= 0) {
SFT_GMetrics mtx;
if (sft_gmetrics(&pFont, gid, &mtx) < 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to get glyph metrics");
return;
}
if (charcode == '\n') {
pen.y += ft_face->size->metrics.height >> 6;
pen.x = x;
continue;
if (*string == '\n') {
penY += mtx.minHeight;
penX = x;
continue;
}
textureWidth = (mtx.minWidth + 3) & ~3;
textureHeight = mtx.minHeight;
SFT_Image img = {
.pixels = nullptr,
.width = textureWidth,
.height = textureHeight,
};
if (textureWidth == 0) {
textureWidth = 4;
}
if (textureHeight == 0) {
textureHeight = 4;
}
auto buffer = make_unique_nothrow<uint8_t[]>((uint32_t) (img.width * img.height));
if (!buffer) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for glyph");
return;
}
img.pixels = buffer.get();
if (sft_render(&pFont, gid, img) < 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to render glyph");
return;
} else {
draw_freetype_bitmap(&img, (int32_t) (penX + mtx.leftSideBearing), (int32_t) (penY + mtx.yOffset));
penX += (int32_t) mtx.advanceWidth;
}
}
FT_Load_Glyph(ft_face, FT_Get_Char_Index(ft_face, charcode), FT_LOAD_DEFAULT);
FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
draw_freetype_bitmap(&slot->bitmap, pen.x + slot->bitmap_left, pen.y - slot->bitmap_top);
pen.x += slot->advance.x >> 6;
}
}
uint32_t DrawUtils::getTextWidth(const char *string) {
wchar_t *buffer = new wchar_t[strlen(string) + 1];
auto *buffer = new wchar_t[strlen(string) + 1];
size_t num = mbstowcs(buffer, string, strlen(string));
if (num > 0) {
@ -297,14 +350,18 @@ uint32_t DrawUtils::getTextWidth(const char *string) {
}
uint32_t DrawUtils::getTextWidth(const wchar_t *string) {
FT_GlyphSlot slot = ft_face->glyph;
uint32_t width = 0;
uint32_t width = 0;
for (; *string; string++) {
FT_Load_Glyph(ft_face, FT_Get_Char_Index(ft_face, *string), FT_LOAD_BITMAP_METRICS_ONLY);
width += slot->advance.x >> 6;
SFT_Glyph gid; // unsigned long gid;
if (sft_lookup(&pFont, *string, &gid) >= 0) {
SFT_GMetrics mtx;
if (sft_gmetrics(&pFont, gid, &mtx) < 0) {
DEBUG_FUNCTION_LINE_ERR("bad glyph metrics");
}
width += (int32_t) mtx.advanceWidth;
}
}
return width;
return (uint32_t) width;
}

View File

@ -1,15 +1,27 @@
#pragma once
#include "schrift.h"
#include <cstdint>
#define COLOR_WHITE Color(0xffffffff)
#define COLOR_BLACK Color(0, 0, 0, 255)
#define COLOR_RED Color(237, 28, 36, 255)
#define COLOR_BACKGROUND Color(0, 40, 100, 255)
#define COLOR_TEXT COLOR_WHITE
#define COLOR_TEXT2 Color(0xB3ffffff)
#define COLOR_AUTOBOOT Color(0xaeea00ff)
#define COLOR_BORDER Color(204, 204, 204, 255)
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4ff)
// visible screen sizes
#define SCREEN_WIDTH 854
#define SCREEN_HEIGHT 480
#define SCREEN_WIDTH 854
#define SCREEN_HEIGHT 480
union Color {
Color(uint32_t color) {
explicit Color(uint32_t color) {
this->color = color;
}
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
this->r = r;
this->g = g;
@ -17,7 +29,7 @@ union Color {
this->a = a;
}
uint32_t color;
uint32_t color{};
struct {
uint8_t r;
uint8_t g;
@ -29,25 +41,39 @@ union Color {
class DrawUtils {
public:
static void initBuffers(void *tvBuffer, uint32_t tvSize, void *drcBuffer, uint32_t drcSize);
static void beginDraw();
static void endDraw();
static void clear(Color col);
static void drawPixel(uint32_t x, uint32_t y, Color col) { drawPixel(x, y, col.r, col.g, col.b, col.a); }
static void drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
static void drawRectFilled(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color col);
static void drawRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t borderSize, Color col);
static void drawBitmap(uint32_t x, uint32_t y, uint32_t target_width, uint32_t target_height, const uint8_t *data);
static void drawPNG(uint32_t x, uint32_t y, const uint8_t *data);
static void initFont();
static bool initFont();
static void deinitFont();
static void setFontSize(uint32_t size);
static void setFontColor(Color col);
static void print(uint32_t x, uint32_t y, const char *string, bool alignRight = false);
static void print(uint32_t x, uint32_t y, const wchar_t *string, bool alignRight = false);
static uint32_t getTextWidth(const char *string);
static uint32_t getTextWidth(const wchar_t *string);
private:

140
source/utils/InputUtils.cpp Normal file
View File

@ -0,0 +1,140 @@
#include "InputUtils.h"
#include <coreinit/thread.h>
#include <padscore/kpad.h>
#include <padscore/wpad.h>
#include <vpad/input.h>
uint32_t remapWiiMoteButtons(uint32_t buttons) {
uint32_t convButtons = 0;
if (buttons & WPAD_BUTTON_LEFT)
convButtons |= VPAD_BUTTON_LEFT;
if (buttons & WPAD_BUTTON_RIGHT)
convButtons |= VPAD_BUTTON_RIGHT;
if (buttons & WPAD_BUTTON_DOWN)
convButtons |= VPAD_BUTTON_DOWN;
if (buttons & WPAD_BUTTON_UP)
convButtons |= VPAD_BUTTON_UP;
if (buttons & WPAD_BUTTON_PLUS)
convButtons |= VPAD_BUTTON_PLUS;
if (buttons & WPAD_BUTTON_2)
convButtons |= VPAD_BUTTON_Y;
if (buttons & WPAD_BUTTON_1)
convButtons |= VPAD_BUTTON_X;
if (buttons & WPAD_BUTTON_B)
convButtons |= VPAD_BUTTON_B;
if (buttons & WPAD_BUTTON_A)
convButtons |= VPAD_BUTTON_A;
if (buttons & WPAD_BUTTON_MINUS)
convButtons |= VPAD_BUTTON_MINUS;
if (buttons & WPAD_BUTTON_HOME)
convButtons |= VPAD_BUTTON_HOME;
return convButtons;
}
uint32_t remapClassicButtons(uint32_t buttons) {
uint32_t convButtons = 0;
if (buttons & WPAD_CLASSIC_BUTTON_LEFT)
convButtons |= VPAD_BUTTON_LEFT;
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT)
convButtons |= VPAD_BUTTON_RIGHT;
if (buttons & WPAD_CLASSIC_BUTTON_DOWN)
convButtons |= VPAD_BUTTON_DOWN;
if (buttons & WPAD_CLASSIC_BUTTON_UP)
convButtons |= VPAD_BUTTON_UP;
if (buttons & WPAD_CLASSIC_BUTTON_PLUS)
convButtons |= VPAD_BUTTON_PLUS;
if (buttons & WPAD_CLASSIC_BUTTON_X)
convButtons |= VPAD_BUTTON_X;
if (buttons & WPAD_CLASSIC_BUTTON_Y)
convButtons |= VPAD_BUTTON_Y;
if (buttons & WPAD_CLASSIC_BUTTON_B)
convButtons |= VPAD_BUTTON_B;
if (buttons & WPAD_CLASSIC_BUTTON_A)
convButtons |= VPAD_BUTTON_A;
if (buttons & WPAD_CLASSIC_BUTTON_MINUS)
convButtons |= VPAD_BUTTON_MINUS;
if (buttons & WPAD_CLASSIC_BUTTON_HOME)
convButtons |= VPAD_BUTTON_HOME;
if (buttons & WPAD_CLASSIC_BUTTON_ZR)
convButtons |= VPAD_BUTTON_ZR;
if (buttons & WPAD_CLASSIC_BUTTON_ZL)
convButtons |= VPAD_BUTTON_ZL;
if (buttons & WPAD_CLASSIC_BUTTON_R)
convButtons |= VPAD_BUTTON_R;
if (buttons & WPAD_CLASSIC_BUTTON_L)
convButtons |= VPAD_BUTTON_L;
return convButtons;
}
InputUtils::InputData InputUtils::getControllerInput() {
InputData inputData = {};
VPADStatus vpadStatus = {};
VPADReadError vpadError = VPAD_READ_UNINITIALIZED;
int maxAttempts = 100;
do {
if (VPADRead(VPAD_CHAN_0, &vpadStatus, 1, &vpadError) > 0 && vpadError == VPAD_READ_SUCCESS) {
inputData.trigger = vpadStatus.trigger;
inputData.hold = vpadStatus.hold;
inputData.release = vpadStatus.release;
} else {
OSSleepTicks(OSMillisecondsToTicks(1));
}
} while (--maxAttempts > 0 && vpadError == VPAD_READ_NO_SAMPLES);
KPADStatus kpadStatus = {};
KPADError kpadError = KPAD_ERROR_UNINITIALIZED;
for (int32_t i = 0; i < 4; i++) {
if (KPADReadEx((KPADChan) i, &kpadStatus, 1, &kpadError) > 0) {
if (kpadError == KPAD_ERROR_OK && kpadStatus.extensionType != 0xFF) {
if (kpadStatus.extensionType == WPAD_EXT_CORE || kpadStatus.extensionType == WPAD_EXT_NUNCHUK) {
inputData.trigger |= remapWiiMoteButtons(kpadStatus.trigger);
inputData.hold |= remapWiiMoteButtons(kpadStatus.hold);
inputData.release |= remapWiiMoteButtons(kpadStatus.release);
} else {
inputData.trigger |= remapClassicButtons(kpadStatus.classic.trigger);
inputData.hold |= remapClassicButtons(kpadStatus.classic.hold);
inputData.release |= remapClassicButtons(kpadStatus.classic.release);
}
}
}
}
return inputData;
}
void InputUtils::Init() {
KPADInit();
WPADEnableURCC(1);
}
void InputUtils::DeInit() {
KPADShutdown();
}

17
source/utils/InputUtils.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <cstdint>
#include <vpad/input.h>
class InputUtils {
public:
typedef struct InputData {
uint32_t trigger = 0;
uint32_t hold = 0;
uint32_t release = 0;
} InputData;
static void Init();
static void DeInit();
static InputData getControllerInput();
};

199
source/utils/MemoryUtils.h Normal file
View File

@ -0,0 +1,199 @@
#pragma once
#include "logger.h"
#include <coreinit/memexpheap.h>
#include <coreinit/memheap.h>
#include <cstdint>
#include <cstring>
#include <optional>
typedef void (*FreeMemoryFn)(void *);
class MemoryWrapper {
public:
MemoryWrapper(void *ptr, uint32_t size, FreeMemoryFn freeFn) : mPtr(ptr), mSize(size), mFreeFn(freeFn) {
}
~MemoryWrapper() {
if (mPtr && mFreeFn) {
memset(mPtr, 0, mSize);
mFreeFn(mPtr);
}
}
MemoryWrapper(const MemoryWrapper &) = delete;
MemoryWrapper &operator=(const MemoryWrapper &) = delete;
MemoryWrapper(MemoryWrapper &&other) noexcept
: mPtr(other.mPtr), mSize(other.mSize), mFreeFn(other.mFreeFn) {
other.mPtr = {};
other.mSize = {};
other.mFreeFn = {};
}
MemoryWrapper &operator=(MemoryWrapper &&other) noexcept {
if (this != &other) {
mPtr = other.mPtr;
mSize = other.mSize;
mFreeFn = other.mFreeFn;
other.mPtr = {};
other.mSize = 0;
other.mFreeFn = {};
}
return *this;
}
[[nodiscard]] void *data() const {
return mPtr;
}
[[nodiscard]] uint32_t size() const {
return mSize;
}
[[nodiscard]] bool IsAllocated() const {
return mFreeFn && mPtr && mSize > 0;
}
private:
void *mPtr = {};
uint32_t mSize = 0;
FreeMemoryFn mFreeFn = {};
};
class ExpHeapMemory {
public:
ExpHeapMemory(MEMHeapHandle heapHandle, void *data, uint32_t size) : mHeapHandle(heapHandle),
mData(data),
mSize(size) {
}
ExpHeapMemory() = default;
~ExpHeapMemory() {
if (mData) {
MEMFreeToExpHeap(mHeapHandle, mData);
}
mData = nullptr;
mSize = 0;
}
// Delete the copy constructor and copy assignment operator
ExpHeapMemory(const ExpHeapMemory &) = delete;
ExpHeapMemory &operator=(const ExpHeapMemory &) = delete;
ExpHeapMemory(ExpHeapMemory &&other) noexcept
: mHeapHandle(other.mHeapHandle), mData(other.mData), mSize(other.mSize) {
other.mHeapHandle = {};
other.mData = {};
other.mSize = 0;
}
ExpHeapMemory &operator=(ExpHeapMemory &&other) noexcept {
if (this != &other) {
mHeapHandle = other.mHeapHandle;
mData = other.mData;
mSize = other.mSize;
other.mHeapHandle = {};
other.mData = {};
other.mSize = 0;
}
return *this;
}
explicit operator bool() const {
return mData != nullptr;
}
explicit operator void *() const {
// Return the desired void* value
return mData;
}
[[nodiscard]] void *data() const {
return mData;
}
[[nodiscard]] std::size_t size() const {
return mSize;
}
static std::optional<ExpHeapMemory> Alloc(MEMHeapHandle heapHandle, uint32_t size, int32_t alignment) {
auto *ptr = MEMAllocFromExpHeapEx(heapHandle, size, alignment);
if (!ptr) {
return {};
}
return ExpHeapMemory(heapHandle, ptr, size);
}
private:
MEMHeapHandle mHeapHandle{};
void *mData = nullptr;
uint32_t mSize{};
};
class HeapWrapper {
public:
explicit HeapWrapper(MemoryWrapper &&memory) : mMemory(std::move(memory)) {
mHeapHandle = MEMCreateExpHeapEx(mMemory.data(), mMemory.size(), MEM_HEAP_FLAG_USE_LOCK);
if (mHeapHandle) {
mSize = mMemory.size();
mPtr = mMemory.data();
}
}
~HeapWrapper() {
if (mHeapHandle) {
MEMDestroyExpHeap(mHeapHandle);
}
if (mPtr) {
memset(mPtr, 0, mSize);
}
}
// Delete the copy constructor and copy assignment operator
HeapWrapper(const HeapWrapper &) = delete;
HeapWrapper &operator=(const HeapWrapper &) = delete;
HeapWrapper(HeapWrapper &&other) noexcept
: mMemory(std::move(other.mMemory)), mHeapHandle(other.mHeapHandle), mPtr(other.mPtr), mSize(other.mSize) {
other.mHeapHandle = {};
other.mPtr = {};
other.mSize = 0;
}
HeapWrapper &operator=(HeapWrapper &&other) noexcept {
if (this != &other) {
mMemory = std::move(other.mMemory);
mHeapHandle = other.mHeapHandle;
mPtr = other.mPtr;
mSize = other.mSize;
other.mHeapHandle = {};
other.mPtr = {};
other.mSize = 0;
}
return *this;
}
[[nodiscard]] MEMHeapHandle GetHeapHandle() const {
return mHeapHandle;
}
[[nodiscard]] uint32_t GetHeapSize() const {
return mSize;
}
[[nodiscard]] bool IsAllocated() const {
return mMemory.IsAllocated();
}
[[nodiscard]] std::optional<ExpHeapMemory> Alloc(uint32_t size, int align) const {
return ExpHeapMemory::Alloc(mHeapHandle, size, align);
}
private:
MemoryWrapper mMemory;
MEMHeapHandle mHeapHandle = {};
void *mPtr = {};
uint32_t mSize = 0;
};

239
source/utils/PairUtils.cpp Normal file
View File

@ -0,0 +1,239 @@
#include "PairUtils.h"
#include "DrawUtils.h"
#include "InputUtils.h"
#include "logger.h"
#include "utils.h"
#include <coreinit/cache.h>
#include <coreinit/thread.h>
#include <malloc.h>
#include <nn/ccr/sys.h>
#include <padscore/kpad.h>
#include <padscore/wpad.h>
#include <vpad/input.h>
void PairMenu::drawPairKPADScreen() const {
DrawUtils::beginDraw();
DrawUtils::clear(COLOR_BACKGROUND);
DrawUtils::setFontColor(COLOR_TEXT);
DrawUtils::setFontSize(26);
std::string textLine1 = "Press the SYNC Button on the controller you want to pair.";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine1.c_str()) / 2, 40, textLine1.c_str(), true);
WPADExtensionType ext{};
for (int i = 0; i < 4; i++) {
bool isConnected = WPADProbe((WPADChan) i, &ext) == 0;
std::string textLine = string_format("Slot %d: ", i + 1);
if (isConnected) {
textLine += ext == WPAD_EXT_PRO_CONTROLLER ? "Pro Controller" : "Wiimote";
} else {
textLine += "No controller";
}
DrawUtils::print(300, 140 + (i * 30), textLine.c_str());
}
DrawUtils::setFontSize(26);
std::string gamepadSyncText1 = "If you are pairing a Wii U GamePad, press the SYNC Button";
std::string gamepadSyncText2 = "on your Wii U console one more time";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(gamepadSyncText1.c_str()) / 2, SCREEN_HEIGHT - 100, gamepadSyncText1.c_str(), true);
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(gamepadSyncText2.c_str()) / 2, SCREEN_HEIGHT - 70, gamepadSyncText2.c_str(), true);
DrawUtils::setFontSize(16);
const char *exitHints = "Press \ue001 to return";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHints) / 2, SCREEN_HEIGHT - 8, exitHints, true);
DrawUtils::endDraw();
}
void PairMenu::drawPairScreen() const {
DrawUtils::beginDraw();
DrawUtils::clear(COLOR_BACKGROUND);
DrawUtils::setFontColor(COLOR_TEXT);
// Convert the pin to symbols and set the text
static char pinSymbols[][4] = {
"\u2660",
"\u2665",
"\u2666",
"\u2663"};
uint32_t pincode = mGamePadPincode;
std::string pin = std::string(pinSymbols[(pincode / 1000) % 10]) +
pinSymbols[(pincode / 100) % 10] +
pinSymbols[(pincode / 10) % 10] +
pinSymbols[pincode % 10];
std::string textLine1 = "Press the SYNC Button on the Wii U GamePad,";
std::string textLine2 = "and enter the four symbols shown below.";
DrawUtils::setFontSize(26);
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine1.c_str()) / 2, 60, textLine1.c_str(), true);
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine2.c_str()) / 2, 100, textLine2.c_str(), true);
DrawUtils::setFontSize(100);
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(pin.c_str()) / 2, (SCREEN_HEIGHT / 2) + 40, pin.c_str(), true);
DrawUtils::setFontSize(20);
std::string textLine3 = string_format("(%d seconds remaining) ", mGamePadSyncTimeout - (uint32_t) (OSTicksToSeconds(OSGetTime() - mSyncGamePadStartTime)));
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine3.c_str()) / 2, SCREEN_HEIGHT - 80, textLine3.c_str(), true);
DrawUtils::setFontSize(26);
std::string textLine4 = "Press the SYNC Button on the Wii U console to exit.";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(textLine4.c_str()) / 2, SCREEN_HEIGHT - 40, textLine4.c_str(), true);
DrawUtils::endDraw();
}
PairMenu::PairMenu() {
CCRSysInit();
mState = STATE_WAIT;
mGamePadSyncTimeout = 120;
// Initialize IM
mIMHandle = IM_Open();
if (mIMHandle < 0) {
DEBUG_FUNCTION_LINE_ERR("PairMenu: IM_Open failed");
OSFatal("EnvironmentLoader: PairMenu: IM_Open failed");
}
mIMRequest = (IMRequest *) memalign(0x40, sizeof(IMRequest));
// Allocate a separate request for IM_CancelGetEventNotify to avoid conflict with the pending IM_GetEventNotify request
mIMCancelRequest = (IMRequest *) memalign(0x40, sizeof(IMRequest));
if (!mIMRequest || !mIMCancelRequest) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate im request");
OSFatal("EnvironmentLoader: PairMenu: Failed to allocate im request");
}
mIMEventMask = IM_EVENT_SYNC;
// Notify about sync button events
IM_GetEventNotify(mIMHandle, mIMRequest, &mIMEventMask, PairMenu::SyncButtonCallback, this);
}
PairMenu::~PairMenu() {
// Close IM
IM_CancelGetEventNotify(mIMHandle, mIMCancelRequest, nullptr, nullptr);
IM_Close(mIMHandle);
if (mIMCancelRequest) {
free(mIMCancelRequest);
mIMCancelRequest = {};
}
if (mIMRequest) {
free(mIMRequest);
mIMRequest = {};
}
// Deinit CCRSys
CCRSysExit();
}
bool PairMenu::ProcessPairScreen() {
switch (mState) {
case STATE_SYNC_WPAD: {
// WPAD syncing stops after ~18 seconds, make sure to restart it.
if ((uint32_t) OSTicksToSeconds(OSGetTime() - mSyncWPADStartTime) >= 18) {
WPADStartSyncDevice();
mSyncWPADStartTime = OSGetTime();
}
InputUtils::InputData input = InputUtils::getControllerInput();
// Stop syncing when pressing A or B.
if (input.trigger & (VPAD_BUTTON_A | VPAD_BUTTON_B)) {
mState = STATE_WAIT;
}
break;
}
case STATE_SYNC_GAMEPAD: {
if (CCRSysGetPincode(&mGamePadPincode) != 0) {
DEBUG_FUNCTION_LINE_ERR("CCRSysGetPincode failed");
mState = STATE_WAIT;
break;
}
// Start pairing to slot 0
if (CCRSysStartPairing(0, mGamePadSyncTimeout) != 0) {
DEBUG_FUNCTION_LINE_ERR("CCRSysStartPairing failed.");
mState = STATE_WAIT;
break;
}
// Pairing has started, save start time
mSyncGamePadStartTime = OSGetTime();
mState = STATE_PAIRING;
DEBUG_FUNCTION_LINE("Started GamePad syncing.");
break;
}
case STATE_PAIRING: {
// Get the current pairing state
CCRSysPairingState pairingState = CCRSysGetPairingState();
if (pairingState == CCR_SYS_PAIRING_TIMED_OUT) {
DEBUG_FUNCTION_LINE("GamePad SYNC timed out.");
// Pairing has timed out or was cancelled
CCRSysStopPairing();
mState = STATE_WAIT;
} else if (pairingState == CCR_SYS_PAIRING_FINISHED) {
DEBUG_FUNCTION_LINE("GamePad paired.");
mState = STATE_WAIT;
}
break;
}
case STATE_CANCEL: {
CCRSysStopPairing();
mState = STATE_WAIT;
break;
}
case STATE_WAIT:
break;
}
switch (mState) {
case STATE_WAIT: {
return false;
}
case STATE_SYNC_WPAD:
drawPairKPADScreen();
break;
case STATE_SYNC_GAMEPAD:
case STATE_PAIRING:
case STATE_CANCEL: {
drawPairScreen();
break;
}
}
return true;
}
void PairMenu::SyncButtonCallback(IOSError error, void *arg) {
auto *pairMenu = (PairMenu *) arg;
if (error == IOS_ERROR_OK && pairMenu && (pairMenu->mIMEventMask & IM_EVENT_SYNC)) {
if (pairMenu->mState == STATE_WAIT) {
pairMenu->mState = STATE_SYNC_WPAD;
// We need to restart the WPAD pairing every 18 seconds. For the timing we need to save the current time.
pairMenu->mSyncWPADStartTime = OSGetTime();
} else if (pairMenu->mState == STATE_SYNC_WPAD) {
pairMenu->mState = STATE_SYNC_GAMEPAD;
} else if (pairMenu->mState == STATE_SYNC_GAMEPAD || pairMenu->mState == STATE_PAIRING) {
pairMenu->mState = STATE_CANCEL;
}
OSMemoryBarrier();
IM_GetEventNotify(pairMenu->mIMHandle, pairMenu->mIMRequest, &pairMenu->mIMEventMask, PairMenu::SyncButtonCallback, pairMenu);
}
}

43
source/utils/PairUtils.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include "logger.h"
#include <coreinit/cache.h>
#include <coreinit/im.h>
#include <coreinit/ios.h>
#include <coreinit/time.h>
#include <malloc.h>
#include <nn/ccr/sys.h>
class PairMenu {
public:
PairMenu();
~PairMenu();
bool ProcessPairScreen();
static void SyncButtonCallback(IOSError error, void *arg);
void drawPairScreen() const;
void drawPairKPADScreen() const;
private:
enum PairMenuState {
STATE_WAIT, // Wait for SYNC button press
STATE_SYNC_WPAD,
STATE_SYNC_GAMEPAD,
STATE_PAIRING,
STATE_CANCEL,
};
IOSHandle mIMHandle{};
IMRequest *mIMRequest{};
IMRequest *mIMCancelRequest{};
OSTime mSyncWPADStartTime = 0;
OSTime mSyncGamePadStartTime = 0;
uint32_t mGamePadPincode = 0;
PairMenuState mState = STATE_WAIT;
uint32_t mGamePadSyncTimeout = 120;
IMEventMask mIMEventMask{};
};

View File

@ -34,6 +34,7 @@ extern "C" {
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#else
@ -44,6 +45,7 @@ extern "C" {
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#endif

1460
source/utils/schrift.c Normal file

File diff suppressed because it is too large Load Diff

88
source/utils/schrift.h Normal file
View File

@ -0,0 +1,88 @@
/* This file is part of libschrift.
*
* © 2019-2022 Thomas Oltmann and contributors
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef SCHRIFT_H
#define SCHRIFT_H 1
#include <stddef.h> /* size_t */
#include <stdint.h> /* uint_fast32_t, uint_least32_t */
#ifdef __cplusplus
extern "C" {
#endif
#define SFT_DOWNWARD_Y 0x01
typedef struct SFT SFT;
typedef struct SFT_Font SFT_Font;
typedef uint_least32_t SFT_UChar; /* Guaranteed to be compatible with char32_t. */
typedef uint_fast32_t SFT_Glyph;
typedef struct SFT_LMetrics SFT_LMetrics;
typedef struct SFT_GMetrics SFT_GMetrics;
typedef struct SFT_Kerning SFT_Kerning;
typedef struct SFT_Image SFT_Image;
struct SFT {
SFT_Font *font;
double xScale;
double yScale;
double xOffset;
double yOffset;
int flags;
};
struct SFT_LMetrics {
double ascender;
double descender;
double lineGap;
};
struct SFT_GMetrics {
double advanceWidth;
double leftSideBearing;
int yOffset;
int minWidth;
int minHeight;
};
struct SFT_Kerning {
double xShift;
double yShift;
};
struct SFT_Image {
void *pixels;
int width;
int height;
};
const char *sft_version(void);
SFT_Font *sft_loadmem(const void *mem, size_t size);
void sft_freefont(SFT_Font *font);
int sft_lmetrics(const SFT *sft, SFT_LMetrics *metrics);
int sft_lookup(const SFT *sft, SFT_UChar codepoint, SFT_Glyph *glyph);
int sft_gmetrics(const SFT *sft, SFT_Glyph glyph, SFT_GMetrics *metrics);
int sft_kerning(const SFT *sft, SFT_Glyph leftGlyph, SFT_Glyph rightGlyph,
SFT_Kerning *kerning);
int sft_render(const SFT *sft, SFT_Glyph glyph, SFT_Image image);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -15,3 +15,16 @@ template<class T, class... Args>
std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
}
template<typename... Args>
std::string string_format(const std::string &format, Args... args) {
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
auto size = static_cast<size_t>(size_s);
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
// those work only in powers of 2
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)

118
source/utils/wiiu_zlib.hpp Normal file
View File

@ -0,0 +1,118 @@
#pragma once
/****************************************************************************
* Copyright (C) 2018-2020 Nathan Strong
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "elfio/elfio_utils.hpp"
#include "logger.h"
#include "utils.h"
#include <memory>
#include <zlib.h>
class wiiu_zlib : public ELFIO::compression_interface {
public:
std::unique_ptr<char[]> inflate(const char *data, const ELFIO::endianess_convertor *convertor, ELFIO::Elf_Xword compressed_size, ELFIO::Elf_Xword &uncompressed_size) const override {
read_uncompressed_size(data, convertor, uncompressed_size);
auto result = make_unique_nothrow<char[]>((uint32_t) (uncompressed_size + 1));
if (result == nullptr) {
return nullptr;
}
int z_ret;
z_stream s = {};
s.zalloc = Z_NULL;
s.zfree = Z_NULL;
s.opaque = Z_NULL;
if (inflateInit_(&s, ZLIB_VERSION, sizeof(s)) != Z_OK) {
return nullptr;
}
s.avail_in = compressed_size - 4;
s.next_in = (Bytef *) data;
s.avail_out = uncompressed_size;
s.next_out = (Bytef *) result.get();
z_ret = ::inflate(&s, Z_FINISH);
inflateEnd(&s);
if (z_ret != Z_OK && z_ret != Z_STREAM_END) {
return nullptr;
}
result[uncompressed_size] = '\0';
return result;
}
std::unique_ptr<char[]> deflate(const char *data, const ELFIO::endianess_convertor *convertor, ELFIO::Elf_Xword decompressed_size, ELFIO::Elf_Xword &compressed_size) const override {
auto result = make_unique_nothrow<char[]>((uint32_t) (decompressed_size));
if (result == nullptr) {
return nullptr;
}
int z_ret;
z_stream s = {};
s.zalloc = Z_NULL;
s.zfree = Z_NULL;
s.opaque = Z_NULL;
if ((z_ret = deflateInit(&s, Z_DEFAULT_COMPRESSION)) != Z_OK) {
return nullptr;
}
s.avail_in = decompressed_size;
s.next_in = (Bytef *) data;
s.avail_out = decompressed_size - 4;
s.next_out = (Bytef *) result.get() + 4;
z_ret = ::deflate(&s, Z_FINISH);
compressed_size = decompressed_size - s.avail_out;
deflateEnd(&s);
if (z_ret != Z_OK && z_ret != Z_STREAM_END) {
compressed_size = 0;
return nullptr;
}
write_compressed_size(result, convertor, compressed_size);
result[compressed_size] = '\0';
return result;
}
private:
static void read_uncompressed_size(const char *&data, const ELFIO::endianess_convertor *convertor, ELFIO::Elf_Xword &uncompressed_size) {
union _int32buffer {
uint32_t word;
char bytes[4];
} int32buffer;
memcpy(int32buffer.bytes, data, 4);
data += 4;
uncompressed_size = (*convertor)(int32buffer.word);
}
static void write_compressed_size(std::unique_ptr<char[]> &result, const ELFIO::endianess_convertor *convertor, ELFIO::Elf_Xword compressed_size) {
union _int32buffer {
uint32_t word;
char bytes[4];
} int32buffer;
int32buffer.word = (*convertor)(compressed_size);
memcpy(result.get(), int32buffer.bytes, 4);
}
};

2
source/version.h Normal file
View File

@ -0,0 +1,2 @@
#pragma once
#define ENVIRONMENT_LOADER_VERSION_EXTRA ""