mirror of
https://github.com/wiiu-env/EnvironmentLoader.git
synced 2025-04-22 09:51:24 +02:00
Compare commits
72 Commits
Environmen
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ed5bdca3b9 | ||
![]() |
4ad1400f9e | ||
![]() |
fd803278f2 | ||
![]() |
4d9e4f73c9 | ||
![]() |
be78693cb7 | ||
![]() |
f81ecf0178 | ||
![]() |
95d0ce1385 | ||
![]() |
d9c743febd | ||
![]() |
95014a2123 | ||
![]() |
bdf9e079c8 | ||
![]() |
7332dcaa1d | ||
![]() |
44d07c0e78 | ||
![]() |
e1d48361b6 | ||
![]() |
5536bc79ee | ||
![]() |
b5f62f552d | ||
![]() |
35b8c0eeb7 | ||
![]() |
2054d97e62 | ||
![]() |
bd8992bc11 | ||
![]() |
e4d2dfa5aa | ||
![]() |
83cf3060c8 | ||
![]() |
f60e8a340d | ||
![]() |
10337d5fba | ||
![]() |
7dbd371d5a | ||
![]() |
a6f7df7764 | ||
![]() |
5e4f93ddfa | ||
![]() |
5da6afb310 | ||
![]() |
0c0d73ffa3 | ||
![]() |
b3a7150c5d | ||
![]() |
f57dc4c163 | ||
![]() |
8fdf6d88c4 | ||
![]() |
9a065a8697 | ||
![]() |
41af813a2d | ||
![]() |
3c5cdbba5e | ||
![]() |
ddcee53177 | ||
![]() |
d24e6233d6 | ||
![]() |
25de833405 | ||
![]() |
5f690a0824 | ||
![]() |
27d969e370 | ||
![]() |
1e1a865f23 | ||
![]() |
8e8ce92822 | ||
![]() |
b9dd1613aa | ||
![]() |
c976e0a788 | ||
![]() |
1f6a2e4bf0 | ||
![]() |
37211a4068 | ||
![]() |
74d53f5502 | ||
![]() |
cf1923b8f8 | ||
![]() |
fe17abe0c9 | ||
![]() |
790394a72d | ||
![]() |
bf7db1c4eb | ||
![]() |
70eebb31b0 | ||
![]() |
21da3ebc27 | ||
![]() |
2291856834 | ||
![]() |
446dacdaac | ||
![]() |
65e460606f | ||
![]() |
7eb5d075f3 | ||
![]() |
114f5b08f0 | ||
![]() |
c82f178943 | ||
![]() |
e4b5d5920c | ||
![]() |
a2dededf64 | ||
![]() |
4d8592c3f9 | ||
![]() |
e0a0184560 | ||
![]() |
2e44af129e | ||
![]() |
fb5f06064e | ||
![]() |
9b86283cfd | ||
![]() |
2e61281d0a | ||
![]() |
66dc52a537 | ||
![]() |
bb44c61230 | ||
![]() |
80e48c3c30 | ||
![]() |
9039d91d0a | ||
![]() |
66d282afcc | ||
![]() |
9d95d6ad29 | ||
![]() |
e4edcfd3b4 |
67
.clang-format
Normal file
67
.clang-format
Normal file
@ -0,0 +1,67 @@
|
||||
# Generated from CLion C/C++ Code Style settings
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||
AlignOperands: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Always
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
ColumnLimit: 0
|
||||
CompactNamespaces: false
|
||||
ContinuationIndentWidth: 8
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: All
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
46
.github/workflows/ci.yml
vendored
46
.github/workflows/ci.yml
vendored
@ -6,10 +6,25 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-binary:
|
||||
runs-on: ubuntu-18.04
|
||||
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 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@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
|
||||
@ -20,7 +35,7 @@ jobs:
|
||||
path: "*.rpx"
|
||||
deploy-binary:
|
||||
needs: build-binary
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Get environment variables
|
||||
id: get_repository_name
|
||||
@ -34,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/unknown
|
||||
generate_release_notes: true
|
||||
name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||
files: |
|
||||
./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
32
.github/workflows/pr.yml
vendored
32
.github/workflows/pr.yml
vendored
@ -3,10 +3,36 @@ name: CI-PR
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build-binary:
|
||||
runs-on: ubuntu-18.04
|
||||
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 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@v4
|
||||
- name: build binary with logging
|
||||
run: |
|
||||
docker build . -t builder
|
||||
docker run --rm -v ${PWD}:/project builder make DEBUG=VERBOSE
|
||||
docker run --rm -v ${PWD}:/project builder make clean
|
||||
docker run --rm -v ${PWD}:/project builder make DEBUG=1
|
||||
build-binary:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: clang-format
|
||||
steps:
|
||||
- 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
1
.gitignore
vendored
@ -12,3 +12,4 @@ cmake-build-debug/
|
||||
*.txt
|
||||
build1/
|
||||
cmake-build-default/
|
||||
*.zip
|
||||
|
@ -1,3 +1,3 @@
|
||||
FROM wiiuenv/devkitppc:20211106
|
||||
FROM ghcr.io/wiiu-env/devkitppc:20240704
|
||||
|
||||
WORKDIR project
|
||||
WORKDIR project
|
||||
|
674
LICENSE
Normal file
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
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/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
19
Makefile
19
Makefile
@ -31,22 +31,27 @@ INCLUDES := source
|
||||
#-------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#-------------------------------------------------------------------------------
|
||||
CFLAGS := -g -Wall -O3 -ffunction-sections -fno-exceptions -fno-rtti\
|
||||
CFLAGS := -g -Wall -Wextra -O2 -ffunction-sections \
|
||||
$(MACHDEP)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
ifeq ($(DEBUG),1)
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
CCFLAGS += -DDEBUG -g
|
||||
CFLAGS += -DDEBUG -g
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),VERBOSE)
|
||||
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
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
|
||||
@ -95,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)
|
||||
|
||||
@ -105,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
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
44
README.md
44
README.md
@ -1,23 +1,36 @@
|
||||
# Setup payload
|
||||
[](https://github.com/wiiu-env/EnvironmentLoader/actions/workflows/ci.yml)
|
||||
|
||||
# Environment Loader
|
||||
This is a payload that should be run with [CustomRPXLoader](https://github.com/wiiu-env/CustomRPXLoader).
|
||||
|
||||
## Usage
|
||||
Put the `payload.rpx` in the `sd:/wiiu/` folder of your sd card and use the `CustomRPXLoader` to run this setup payload.
|
||||
Put the `payload.rpx` in the `sd:/wiiu/` folder of your sd card and use the `CustomRPXLoader` to run this setup payload, hold X on the Gamepad while loading to force open the menu.
|
||||
|
||||
This payload checks for enviroments in the following directory: `sd:/wiiu/environments/`.
|
||||
Per default it's booting `sd:/wiiu/environments/default`, to choose which environment will be booted, hold **X** on the gamepad while launching.
|
||||
|
||||
Example file structure for having a `tiramisu` and a `installer` environment on the sd card:
|
||||
```
|
||||
sd:\wiiu\environments\tiramisu\modules\setup\00_mocha.rpx
|
||||
sd:\wiiu\environments\tiramisu\modules\setup\01_other_cool_payload.rpx
|
||||
sd:\wiiu\environments\installer\modules\setup\00_mocha.rpx
|
||||
sd:\wiiu\environments\installer\modules\setup\01_installer_launcher.rpx
|
||||
```
|
||||
|
||||
When you start the EnvironmentLoader a selection menu appears. Use Y on the Gamepad to set a default enviroment.
|
||||
To open the selection menu when a default enviroment is set, hold X on the Gamepad while launching the EnvironmentLoader.
|
||||
|
||||
When launching an given enviroment, all `.rpx` files in `[ENVIRONMENT]/modules/setup` will be run.
|
||||
- Make sure not to call `exit` in the setup payloads
|
||||
- The one time setups will be run in the order of their ordered filenames.
|
||||
- The files will be run in the order of their ordered filenames.
|
||||
|
||||
Example file structure for having a `default` and a `installer` environment on the sd card:
|
||||
```
|
||||
sd:\wiiu\environments\default\modules\setup\00_mocha.rpx
|
||||
sd:\wiiu\environments\default\modules\setup\01_other_cool_payload.rpx
|
||||
sd:\wiiu\environments\installer\modules\setup\00_mocha.rpx
|
||||
sd:\wiiu\environments\installer\modules\setup\01_installer_auncher.rpx
|
||||
```
|
||||
## Buildflags
|
||||
|
||||
### Logging
|
||||
Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`.
|
||||
|
||||
`make` Logs errors only (via OSReport).
|
||||
`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||
`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||
|
||||
## Building
|
||||
Make you to have [wut](https://github.com/devkitPro/wut/) installed and use the following command for build:
|
||||
@ -40,9 +53,12 @@ docker run -it --rm -v ${PWD}:/project environmentloader-builder make
|
||||
docker run -it --rm -v ${PWD}:/project environmentloader-builder make clean
|
||||
```
|
||||
|
||||
## Format the code via docker
|
||||
|
||||
`docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source --exclude ./source/elfio -i`
|
||||
|
||||
## Credits
|
||||
- maschell
|
||||
- Copy paste stuff from dimok
|
||||
- Copy pasted the solution for using wut header in .elf files from [RetroArch](https://github.com/libretro/RetroArch)
|
||||
- Copy pasted resolving the ElfRelocations from [decaf](https://github.com/decaf-emu/decaf-emu)
|
||||
- Copy pasted stuff from dimok
|
||||
- Copy pasted resolving the ElfRelocations from [decaf](https://github.com/decaf-emu/decaf-emu)
|
||||
- https://github.com/serge1/ELFIO
|
||||
|
@ -1,156 +1,61 @@
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memdefaultheap.h>
|
||||
#include <whb/sdcard.h>
|
||||
#include <whb/file.h>
|
||||
#include <whb/log.h>
|
||||
#include <bits/shared_ptr.h>
|
||||
#include <coreinit/dynload.h>
|
||||
#include "utils/logger.h"
|
||||
#include <bits/shared_ptr.h>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/dynload.h>
|
||||
|
||||
#include "elfio/elfio.hpp"
|
||||
#include "ElfUtils.h"
|
||||
#include "elfio/elfio.hpp"
|
||||
|
||||
int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t *sizeOut) {
|
||||
char path[256];
|
||||
int result = 0;
|
||||
char *sdRootPath = nullptr;
|
||||
if (!WHBMountSdCard()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to mount SD Card...");
|
||||
result = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sdRootPath = WHBGetSdCardMountPath();
|
||||
sprintf(path, "%s/%s", sdRootPath, relativefilepath);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Loading file %s.", path);
|
||||
|
||||
*fileOut = WHBReadWholeFile(path, sizeOut);
|
||||
if (!(*fileOut)) {
|
||||
result = -2;
|
||||
DEBUG_FUNCTION_LINE("WHBReadWholeFile(%s) returned NULL", path);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
WHBUnmountSdCard();
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t load_loader_elf_from_sd(unsigned char *baseAddress, const char *relativePath) {
|
||||
char *elf_data = nullptr;
|
||||
uint32_t fileSize = 0;
|
||||
if (LoadFileToMem(relativePath, &elf_data, &fileSize) != 0) {
|
||||
OSFatal("Failed to load hook_payload.elf from the SD Card.");
|
||||
}
|
||||
uint32_t result = load_loader_elf(baseAddress, elf_data, fileSize);
|
||||
|
||||
MEMFreeToDefaultHeap((void *) elf_data);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize) {
|
||||
ELFIO::Elf32_Ehdr *ehdr;
|
||||
ELFIO::Elf32_Phdr *phdrs;
|
||||
uint8_t *image;
|
||||
int32_t i;
|
||||
|
||||
ehdr = (ELFIO::Elf32_Ehdr *) elf_data;
|
||||
|
||||
if (ehdr->e_phoff == 0 || ehdr->e_phnum == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ehdr->e_phentsize != sizeof(ELFIO::Elf32_Phdr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
phdrs = (ELFIO::Elf32_Phdr *) (elf_data + ehdr->e_phoff);
|
||||
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
if (phdrs[i].p_type != PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (phdrs[i].p_filesz > phdrs[i].p_memsz) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!phdrs[i].p_filesz) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t p_paddr = phdrs[i].p_paddr + (uint32_t) baseAddress;
|
||||
image = (uint8_t *) (elf_data + phdrs[i].p_offset);
|
||||
|
||||
memcpy((void *) p_paddr, image, phdrs[i].p_filesz);
|
||||
DCFlushRange((void *) p_paddr, phdrs[i].p_filesz);
|
||||
|
||||
if (phdrs[i].p_flags & PF_X) {
|
||||
ICInvalidateRange((void *) p_paddr, phdrs[i].p_memsz);
|
||||
}
|
||||
}
|
||||
|
||||
//! clear BSS
|
||||
auto *shdr = (ELFIO::Elf32_Shdr *) (elf_data + ehdr->e_shoff);
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
const char *section_name = ((const char *) elf_data) + shdr[ehdr->e_shstrndx].sh_offset + shdr[i].sh_name;
|
||||
if (section_name[0] == '.' && section_name[1] == 'b' && section_name[2] == 's' && section_name[3] == 's') {
|
||||
memset((void *) (shdr[i].sh_addr + baseAddress), 0, shdr[i].sh_size);
|
||||
DCFlushRange((void *) (shdr[i].sh_addr + baseAddress), shdr[i].sh_size);
|
||||
} else if (section_name[0] == '.' && section_name[1] == 's' && section_name[2] == 'b' && section_name[3] == 's' && section_name[4] == 's') {
|
||||
memset((void *) (shdr[i].sh_addr + baseAddress), 0, shdr[i].sh_size);
|
||||
DCFlushRange((void *) (shdr[i].sh_addr + baseAddress), shdr[i].sh_size);
|
||||
}
|
||||
}
|
||||
|
||||
return ehdr->e_entry;
|
||||
}
|
||||
|
||||
|
||||
bool ElfUtils::doRelocation(std::vector<std::shared_ptr<RelocationData>> &relocData, relocation_trampolin_entry_t *tramp_data, uint32_t tramp_length) {
|
||||
for (auto const &curReloc: relocData) {
|
||||
std::string functionName = curReloc->getName();
|
||||
std::string rplName = curReloc->getImportRPLInformation()->getName();
|
||||
int32_t isData = curReloc->getImportRPLInformation()->isData();
|
||||
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();
|
||||
OSDynLoad_Module rplHandle = nullptr;
|
||||
|
||||
|
||||
auto err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
|
||||
if (err != OS_DYNLOAD_OK || rplHandle == 0) {
|
||||
// only acquire if not already loaded.
|
||||
auto res = 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) {
|
||||
DEBUG_FUNCTION_LINE("Failed to find export for %s %s %d", functionName.c_str(), rplName.c_str(), isData);
|
||||
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("Relocation failed\n");
|
||||
DEBUG_FUNCTION_LINE_ERR("Relocation failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampolin_entry_t));
|
||||
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampolin_entry_t));
|
||||
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
// See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144
|
||||
bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampolin_entry_t *trampolin_data, uint32_t trampolin_data_length,
|
||||
bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||
RelocationType reloc_type) {
|
||||
if (type == R_PPC_NONE) {
|
||||
return true;
|
||||
}
|
||||
auto target = destination + offset;
|
||||
auto value = symbol_addr + addend;
|
||||
|
||||
auto target = destination + offset;
|
||||
auto value = symbol_addr + addend;
|
||||
|
||||
auto relValue = value - static_cast<uint32_t>(target);
|
||||
|
||||
@ -170,7 +75,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
*((uint16_t *) (target)) = static_cast<uint16_t>((value + 0x8000) >> 16);
|
||||
break;
|
||||
case R_PPC_DTPMOD32:
|
||||
DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n");
|
||||
DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME");
|
||||
//*((int32_t *)(target)) = tlsModuleIndex;
|
||||
break;
|
||||
case R_PPC_DTPREL32:
|
||||
@ -188,18 +93,18 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
case R_PPC_REL14: {
|
||||
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
if (distance > 0x7FFC || distance < -0x7FFC) {
|
||||
DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target.");
|
||||
DEBUG_FUNCTION_LINE_ERR("***14-bit relative branch cannot hit target.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance & 3) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((distance >= 0 && (distance & 0xFFFF8000)) ||
|
||||
(distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -213,42 +118,48 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
// }
|
||||
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
|
||||
if (trampolin_data == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin isn't provided\n");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
|
||||
if (trampoline_data == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided");
|
||||
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance);
|
||||
return false;
|
||||
} else {
|
||||
relocation_trampolin_entry_t *freeSlot = nullptr;
|
||||
for (uint32_t i = 0; i < trampolin_data_length; i++) {
|
||||
relocation_trampoline_entry_t *freeSlot = nullptr;
|
||||
for (uint32_t i = 0; i < trampoline_data_length; i++) {
|
||||
// We want to override "old" relocations of imports
|
||||
// Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS.
|
||||
// When all relocations are done successfully, they will be turned into RELOC_TRAMP_IMPORT_DONE
|
||||
// so they can be overridden/updated/reused on the next application launch.
|
||||
//
|
||||
// Relocations that won't change will have the status RELOC_TRAMP_FIXED and are set to free when the module is unloaded.
|
||||
if (trampolin_data[i].status == RELOC_TRAMP_FREE ||
|
||||
trampolin_data[i].status == RELOC_TRAMP_IMPORT_DONE) {
|
||||
freeSlot = &(trampolin_data[i]);
|
||||
if (trampoline_data[i].status == RELOC_TRAMP_FREE ||
|
||||
trampoline_data[i].status == RELOC_TRAMP_IMPORT_DONE) {
|
||||
freeSlot = &(trampoline_data[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (freeSlot == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin data list is full\n");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) &(freeSlot->trampolin[0])));
|
||||
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline data list is full");
|
||||
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, target - (uint32_t) & (freeSlot->trampoline[0]));
|
||||
return false;
|
||||
}
|
||||
if (target - (uint32_t) &(freeSlot->trampolin[0]) > 0x1FFFFFC) {
|
||||
DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer).");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) &(freeSlot->trampolin[0])));
|
||||
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
|
||||
auto newValue = symbolValue + addend;
|
||||
auto newDistance = static_cast<int32_t>(newValue) - static_cast<int32_t>(target);
|
||||
if (newDistance > 0x1FFFFFC || newDistance < -0x1FFFFFC) {
|
||||
DEBUG_FUNCTION_LINE_ERR("**Cannot link 24-bit jump (too far to tramp buffer).");
|
||||
if (newDistance < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance -%08X", newValue, target, abs(newDistance));
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", newValue, target, newDistance);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
freeSlot->trampolin[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h
|
||||
freeSlot->trampolin[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l
|
||||
freeSlot->trampolin[2] = 0x7D6903A6; // mtctr r11
|
||||
freeSlot->trampolin[3] = 0x4E800420; // bctr
|
||||
DCFlushRange((void *) freeSlot->trampolin, sizeof(freeSlot->trampolin));
|
||||
ICInvalidateRange((unsigned char *) freeSlot->trampolin, sizeof(freeSlot->trampolin));
|
||||
freeSlot->trampoline[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h
|
||||
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
|
||||
ICInvalidateRange((unsigned char *) freeSlot->trampoline, sizeof(freeSlot->trampoline));
|
||||
|
||||
if (reloc_type == RELOC_TYPE_FIXED) {
|
||||
freeSlot->status = RELOC_TRAMP_FIXED;
|
||||
@ -256,24 +167,22 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
// Relocations for the imports may be overridden
|
||||
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
|
||||
}
|
||||
auto symbolValue = (uint32_t) &(freeSlot->trampolin[0]);
|
||||
value = symbolValue + addend;
|
||||
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
distance = newDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if (distance & 3) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance >= 0 && (distance & 0xFE000000)) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -281,8 +190,10 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
||||
DEBUG_FUNCTION_LINE_ERR("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
||||
return false;
|
||||
}
|
||||
ICInvalidateRange(reinterpret_cast<void *>(target), 4);
|
||||
DCFlushRange(reinterpret_cast<void *>(target), 4);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,49 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/relocation_defines.h"
|
||||
#include "module/RelocationData.h"
|
||||
#include <coreinit/dynload.h>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include "common/relocation_defines.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "module/RelocationData.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t *sizeOut);
|
||||
uint32_t load_loader_elf_from_sd(unsigned char *baseAddress, const char *relativePath);
|
||||
uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize);
|
||||
|
||||
#define R_PPC_NONE 0
|
||||
#define R_PPC_ADDR32 1
|
||||
#define R_PPC_ADDR16_LO 4
|
||||
#define R_PPC_ADDR16_HI 5
|
||||
#define R_PPC_ADDR16_HA 6
|
||||
#define R_PPC_REL24 10
|
||||
#define R_PPC_REL14 11
|
||||
#define R_PPC_DTPMOD32 68
|
||||
#define R_PPC_DTPREL32 78
|
||||
#define R_PPC_EMB_SDA21 109
|
||||
#define R_PPC_EMB_RELSDA 116
|
||||
#define R_PPC_DIAB_SDA21_LO 180
|
||||
#define R_PPC_DIAB_SDA21_HI 181
|
||||
#define R_PPC_DIAB_SDA21_HA 182
|
||||
#define R_PPC_DIAB_RELSDA_LO 183
|
||||
#define R_PPC_DIAB_RELSDA_HI 184
|
||||
#define R_PPC_DIAB_RELSDA_HA 185
|
||||
#define R_PPC_GHS_REL16_HA 251
|
||||
#define R_PPC_GHS_REL16_HI 252
|
||||
#define R_PPC_GHS_REL16_LO 253
|
||||
#define R_PPC_NONE 0
|
||||
#define R_PPC_ADDR32 1
|
||||
#define R_PPC_ADDR16_LO 4
|
||||
#define R_PPC_ADDR16_HI 5
|
||||
#define R_PPC_ADDR16_HA 6
|
||||
#define R_PPC_REL24 10
|
||||
#define R_PPC_REL14 11
|
||||
#define R_PPC_DTPMOD32 68
|
||||
#define R_PPC_DTPREL32 78
|
||||
#define R_PPC_EMB_SDA21 109
|
||||
#define R_PPC_EMB_RELSDA 116
|
||||
#define R_PPC_DIAB_SDA21_LO 180
|
||||
#define R_PPC_DIAB_SDA21_HI 181
|
||||
#define R_PPC_DIAB_SDA21_HA 182
|
||||
#define R_PPC_DIAB_RELSDA_LO 183
|
||||
#define R_PPC_DIAB_RELSDA_HI 184
|
||||
#define R_PPC_DIAB_RELSDA_HA 185
|
||||
#define R_PPC_GHS_REL16_HA 251
|
||||
#define R_PPC_GHS_REL16_HI 252
|
||||
#define R_PPC_GHS_REL16_LO 253
|
||||
|
||||
// Masks for manipulating Power PC relocation targets
|
||||
#define PPC_WORD32 0xFFFFFFFF
|
||||
#define PPC_WORD30 0xFFFFFFFC
|
||||
#define PPC_LOW24 0x03FFFFFC
|
||||
#define PPC_LOW14 0x0020FFFC
|
||||
#define PPC_HALF16 0xFFFF
|
||||
#define PPC_WORD32 0xFFFFFFFF
|
||||
#define PPC_WORD30 0xFFFFFFFC
|
||||
#define PPC_LOW24 0x03FFFFFC
|
||||
#define PPC_LOW14 0x0020FFFC
|
||||
#define PPC_HALF16 0xFFFF
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@ -52,9 +48,8 @@ uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fi
|
||||
class ElfUtils {
|
||||
|
||||
public:
|
||||
static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampolin_entry_t *trampolin_data, uint32_t trampolin_data_length,
|
||||
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(std::vector<std::shared_ptr<RelocationData>> &relocData, relocation_trampolin_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);
|
||||
};
|
||||
|
@ -17,20 +17,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DYN_LINK_FUNCTION_NAME_LENGTH 351
|
||||
#define DYN_LINK_IMPORT_NAME_LENGTH 50
|
||||
#define DYN_LINK_FUNCTION_NAME_LENGTH 351
|
||||
#define DYN_LINK_IMPORT_NAME_LENGTH 50
|
||||
|
||||
#define DYN_LINK_FUNCTION_LIST_LENGTH 500
|
||||
#define DYN_LINK_IMPORT_LIST_LENGTH 50
|
||||
#define DYN_LINK_FUNCTION_LIST_LENGTH 500
|
||||
#define DYN_LINK_IMPORT_LIST_LENGTH 50
|
||||
|
||||
#define DYN_LINK_TRAMPOLIN_LIST_LENGTH DYN_LINK_FUNCTION_LIST_LENGTH
|
||||
|
||||
#define DYN_LINK_TRAMPOLIN_LIST_LENGTH DYN_LINK_FUNCTION_LIST_LENGTH
|
||||
|
||||
typedef struct _dyn_linking_function_t {
|
||||
char functionName[DYN_LINK_FUNCTION_NAME_LENGTH + 1];
|
||||
@ -44,8 +45,8 @@ typedef struct _dyn_linking_import_t {
|
||||
|
||||
typedef struct _dyn_linking_relocation_entry_t {
|
||||
dyn_linking_function_t *functionEntry = nullptr;
|
||||
dyn_linking_import_t *importEntry = nullptr;
|
||||
void *destination = NULL;
|
||||
dyn_linking_import_t *importEntry = nullptr;
|
||||
void *destination = NULL;
|
||||
char type{};
|
||||
size_t offset{};
|
||||
int32_t addend{};
|
||||
|
@ -17,17 +17,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "dynamic_linking_defines.h"
|
||||
#include "relocation_defines.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct module_information_t {
|
||||
relocation_trampolin_entry_t trampolines[DYN_LINK_TRAMPOLIN_LIST_LENGTH];
|
||||
relocation_trampoline_entry_t trampolines[DYN_LINK_TRAMPOLIN_LIST_LENGTH];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -19,19 +19,19 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
typedef enum RelocationTrampolinStatus{
|
||||
RELOC_TRAMP_FREE = 0,
|
||||
RELOC_TRAMP_FIXED = 1,
|
||||
RELOC_TRAMP_IMPORT_IN_PROGRESS = 2,
|
||||
RELOC_TRAMP_IMPORT_DONE = 3,
|
||||
} RelocationTrampolinStatus;
|
||||
typedef enum RelocationTrampolineStatus {
|
||||
RELOC_TRAMP_FREE = 0,
|
||||
RELOC_TRAMP_FIXED = 1,
|
||||
RELOC_TRAMP_IMPORT_IN_PROGRESS = 2,
|
||||
RELOC_TRAMP_IMPORT_DONE = 3,
|
||||
} RelocationTrampolineStatus;
|
||||
|
||||
typedef enum RelocationType{
|
||||
RELOC_TYPE_FIXED = 0,
|
||||
RELOC_TYPE_IMPORT = 1
|
||||
typedef enum RelocationType {
|
||||
RELOC_TYPE_FIXED = 0,
|
||||
RELOC_TYPE_IMPORT = 1
|
||||
} RelocationType;
|
||||
|
||||
typedef struct relocation_trampolin_entry_t {
|
||||
uint32_t trampolin[4];
|
||||
RelocationTrampolinStatus status;
|
||||
} relocation_trampolin_entry_t;
|
||||
typedef struct relocation_trampoline_entry_t {
|
||||
uint32_t trampoline[4];
|
||||
RelocationTrampolineStatus status;
|
||||
} relocation_trampoline_entry_t;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
88
source/elfio/elfio_array.hpp
Normal file
88
source/elfio/elfio_array.hpp
Normal 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
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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
|
||||
@ -23,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;
|
||||
}
|
||||
@ -89,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:
|
||||
@ -187,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();
|
||||
|
||||
@ -201,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:
|
||||
@ -218,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:
|
||||
@ -234,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
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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
|
||||
@ -23,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;
|
||||
@ -86,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
|
||||
|
124
source/elfio/elfio_modinfo.hpp
Normal file
124
source/elfio/elfio_modinfo.hpp
Normal 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
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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
|
||||
@ -38,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 );
|
||||
@ -112,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, §ion::get_size>;
|
||||
using const_note_section_accessor =
|
||||
note_section_accessor_template<const section, §ion::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
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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,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 )
|
||||
{
|
||||
@ -37,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 )
|
||||
{
|
||||
@ -48,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 ) {
|
||||
@ -215,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 );
|
||||
@ -264,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 );
|
||||
@ -285,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 )
|
||||
{
|
||||
@ -316,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
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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,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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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
|
||||
@ -23,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 );
|
||||
}
|
||||
@ -133,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
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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
|
||||
@ -30,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
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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,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;
|
||||
|
||||
@ -75,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;
|
||||
|
||||
@ -128,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;
|
||||
}
|
||||
@ -239,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 );
|
||||
@ -261,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
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
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
|
||||
@ -23,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 {
|
||||
@ -182,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;
|
||||
@ -204,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
|
||||
|
1
source/elfio/elfio_version.hpp
Normal file
1
source/elfio/elfio_version.hpp
Normal file
@ -0,0 +1 @@
|
||||
#define ELFIO_VERSION "3.12"
|
179
source/elfio/elfio_versym.hpp
Normal file
179
source/elfio/elfio_versym.hpp
Normal 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
|
@ -1,15 +1,15 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <fs/CFile.hpp>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
CFile::CFile() {
|
||||
iFd = -1;
|
||||
iFd = -1;
|
||||
mem_file = NULL;
|
||||
filesize = 0;
|
||||
pos = 0;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
CFile::CFile(const std::string &filepath, eOpenTypes mode) {
|
||||
@ -35,7 +35,7 @@ int32_t CFile::open(const std::string &filepath, eOpenTypes mode) {
|
||||
|
||||
switch (mode) {
|
||||
default:
|
||||
case ReadOnly: // file must exist
|
||||
case ReadOnly: // file must exist
|
||||
openMode = O_RDONLY;
|
||||
break;
|
||||
case WriteOnly: // file will be created / zerod
|
||||
@ -77,10 +77,10 @@ void CFile::close() {
|
||||
if (iFd >= 0)
|
||||
::close(iFd);
|
||||
|
||||
iFd = -1;
|
||||
iFd = -1;
|
||||
mem_file = NULL;
|
||||
filesize = 0;
|
||||
pos = 0;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
int32_t CFile::read(uint8_t *ptr, size_t size) {
|
||||
@ -127,7 +127,7 @@ int32_t CFile::write(const uint8_t *ptr, size_t size) {
|
||||
}
|
||||
|
||||
int32_t CFile::seek(long int offset, int32_t origin) {
|
||||
int32_t ret = 0;
|
||||
int32_t ret = 0;
|
||||
int64_t newPos = pos;
|
||||
|
||||
if (origin == SEEK_SET) {
|
||||
@ -158,7 +158,7 @@ int32_t CFile::seek(long int offset, int32_t origin) {
|
||||
|
||||
int32_t CFile::fwrite(const char *format, ...) {
|
||||
char tmp[512];
|
||||
tmp[0] = 0;
|
||||
tmp[0] = 0;
|
||||
int32_t result = -1;
|
||||
|
||||
va_list va;
|
||||
@ -171,5 +171,3 @@ int32_t CFile::fwrite(const char *format, ...) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
#ifndef CFILE_HPP_
|
||||
#define CFILE_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
|
@ -24,22 +24,22 @@
|
||||
* DirList Class
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <algorithm>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fs/DirList.h>
|
||||
#include <utils/StringTools.h>
|
||||
|
||||
DirList::DirList() {
|
||||
Flags = 0;
|
||||
Flags = 0;
|
||||
Filter = 0;
|
||||
Depth = 0;
|
||||
Depth = 0;
|
||||
}
|
||||
|
||||
DirList::DirList(const std::string &path, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||
@ -55,9 +55,9 @@ BOOL DirList::LoadPath(const std::string &folder, const char *filter, uint32_t f
|
||||
if (folder.empty())
|
||||
return false;
|
||||
|
||||
Flags = flags;
|
||||
Flags = flags;
|
||||
Filter = filter;
|
||||
Depth = maxDepth;
|
||||
Depth = maxDepth;
|
||||
|
||||
std::string folderpath(folder);
|
||||
uint32_t length = folderpath.size();
|
||||
@ -82,14 +82,14 @@ BOOL DirList::InternalLoadPath(std::string &folderpath) {
|
||||
return false;
|
||||
|
||||
struct dirent *dirent = NULL;
|
||||
DIR *dir = NULL;
|
||||
DIR *dir = NULL;
|
||||
|
||||
dir = opendir(folderpath.c_str());
|
||||
if (dir == NULL)
|
||||
return false;
|
||||
|
||||
while ((dirent = readdir(dir)) != 0) {
|
||||
BOOL isDir = dirent->d_type & DT_DIR;
|
||||
BOOL isDir = dirent->d_type & DT_DIR;
|
||||
const char *filename = dirent->d_name;
|
||||
|
||||
if (isDir) {
|
||||
|
@ -27,8 +27,8 @@
|
||||
#ifndef ___DIRLIST_H_
|
||||
#define ___DIRLIST_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wut_types.h>
|
||||
|
||||
typedef struct {
|
||||
@ -93,10 +93,11 @@ public:
|
||||
|
||||
//! Enum for search/filter flags
|
||||
enum {
|
||||
Files = 0x01,
|
||||
Dirs = 0x02,
|
||||
Files = 0x01,
|
||||
Dirs = 0x02,
|
||||
CheckSubfolders = 0x08,
|
||||
};
|
||||
|
||||
protected:
|
||||
// Internal parser
|
||||
BOOL InternalLoadPath(std::string &path);
|
||||
|
@ -33,23 +33,22 @@ void KernelWriteU32(uint32_t addr, uint32_t value) {
|
||||
}
|
||||
|
||||
/* Write a 32-bit word with kernel permissions */
|
||||
void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value) {
|
||||
asm volatile (
|
||||
"li 3,1\n"
|
||||
"li 4,0\n"
|
||||
"mr 5,%1\n"
|
||||
"li 6,0\n"
|
||||
"li 7,0\n"
|
||||
"lis 8,1\n"
|
||||
"mr 9,%0\n"
|
||||
"mr %1,1\n"
|
||||
"li 0,0x3500\n"
|
||||
"sc\n"
|
||||
"nop\n"
|
||||
"mr 1,%1\n"
|
||||
:
|
||||
: "r"(addr), "r"(value)
|
||||
: "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10",
|
||||
"11", "12"
|
||||
);
|
||||
void __attribute__((noinline)) kern_write(void *addr, uint32_t value) {
|
||||
asm volatile(
|
||||
"li 3,1\n"
|
||||
"li 4,0\n"
|
||||
"mr 5,%1\n"
|
||||
"li 6,0\n"
|
||||
"li 7,0\n"
|
||||
"lis 8,1\n"
|
||||
"mr 9,%0\n"
|
||||
"mr %1,1\n"
|
||||
"li 0,0x3500\n"
|
||||
"sc\n"
|
||||
"nop\n"
|
||||
"mr 1,%1\n"
|
||||
:
|
||||
: "r"(addr), "r"(value)
|
||||
: "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10",
|
||||
"11", "12");
|
||||
}
|
||||
|
@ -2,16 +2,17 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define ADDRESS_main_entry_hook 0x0101C56C
|
||||
#define ADDRESS_main_entry_hook 0x0101C56C
|
||||
|
||||
#define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown
|
||||
#define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games
|
||||
#define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader
|
||||
#define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu
|
||||
#define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL)
|
||||
|
||||
#define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown
|
||||
#define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games
|
||||
#define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader
|
||||
#define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu
|
||||
#define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL)
|
||||
|
||||
void RevertMainHook();
|
||||
|
||||
void KernelWriteU32(uint32_t addr, uint32_t value);
|
||||
|
||||
void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value);
|
||||
void __attribute__((noinline)) kern_write(void *addr, uint32_t value);
|
||||
|
606
source/main.cpp
606
source/main.cpp
@ -1,38 +1,50 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "utils/StringTools.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/dynload.h>
|
||||
#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 <coreinit/foreground.h>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/ios.h>
|
||||
#include <nn/act/client_cpp.h>
|
||||
#include <coreinit/dynload.h>
|
||||
#include <whb/log_udp.h>
|
||||
#include <sysapp/title.h>
|
||||
#include <vector>
|
||||
#include <vpad/input.h>
|
||||
#include <whb/log_cafe.h>
|
||||
#include <whb/log_module.h>
|
||||
#include <vector>
|
||||
#include <coreinit/dynload.h>
|
||||
#include <coreinit/screen.h>
|
||||
#include <memory>
|
||||
#include <malloc.h>
|
||||
#include <vpad/input.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <fcntl.h>
|
||||
#include "utils/StringTools.h"
|
||||
#include <whb/log_udp.h>
|
||||
|
||||
#include "fs/DirList.h"
|
||||
#include "module/ModuleDataFactory.h"
|
||||
#include "ElfUtils.h"
|
||||
#include "kernel.h"
|
||||
#include "common/module_defines.h"
|
||||
#include "fs/DirList.h"
|
||||
#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"
|
||||
|
||||
#define MEMORY_REGION_START 0x00900000
|
||||
#define MEMORY_REGION_SIZE 0x00700000
|
||||
#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"
|
||||
#define MEMORY_REGION_START 0x00800000
|
||||
#define AUTOBOOT_CONFIG_PATH "fs:/vol/external01/wiiu/environments/default.cfg"
|
||||
|
||||
bool CheckRunning() {
|
||||
switch (ProcUIProcessMessages(true)) {
|
||||
@ -59,7 +71,7 @@ extern "C" uint32_t textStart();
|
||||
std::string EnvironmentSelectionScreen(const std::map<std::string, std::string> &payloads, int32_t autobootIndex);
|
||||
|
||||
std::optional<std::string> getFileContent(const std::string &path) {
|
||||
DEBUG_FUNCTION_LINE("Read %s", path.c_str());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Read from file %s", path.c_str());
|
||||
FILE *f = fopen(path.c_str(), "r");
|
||||
if (f) {
|
||||
char buf[128]{};
|
||||
@ -68,12 +80,12 @@ std::optional<std::string> getFileContent(const std::string &path) {
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Failed");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load %s", path.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
bool writeFileContent(const std::string &path, const std::string &content) {
|
||||
DEBUG_FUNCTION_LINE("Write to file %s: %s", path.c_str(), content.c_str());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Write to file %s: %s", path.c_str(), content.c_str());
|
||||
FILE *f = fopen(path.c_str(), "w");
|
||||
if (f) {
|
||||
fputs(content.c_str(), f);
|
||||
@ -83,108 +95,135 @@ bool writeFileContent(const std::string &path, const std::string &content) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
#ifdef DEBUG
|
||||
if (!WHBLogModuleInit()) {
|
||||
WHBLogCafeInit();
|
||||
WHBLogUdpInit();
|
||||
// We need to call __init_wut_malloc somewhere so wut_malloc will be used for the memory allocation.
|
||||
__init_wut_malloc();
|
||||
initLogging();
|
||||
|
||||
if (IOS_Open((char *) ("/dev/iosuhax"), static_cast<IOSOpenMode>(0)) >= 0) {
|
||||
auto checkTiramisuHBL = fopen("fs:/vol/external01/wiiu/environments/tiramisu/modules/setup/50_hbl_installer.rpx", "r");
|
||||
if (checkTiramisuHBL != nullptr) {
|
||||
fclose(checkTiramisuHBL);
|
||||
OSFatal("Don't run the EnvironmentLoader twice.\n\nIf you want to open the Homebrew Launcher, launch the Mii Maker\ninstead.");
|
||||
} else {
|
||||
OSFatal("Don't run the EnvironmentLoader twice.");
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
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;
|
||||
bool noEnvironmentsFound = false;
|
||||
bool shownMenu = false;
|
||||
|
||||
auto gModuleData = (module_information_t *) (textSectionStart - sizeof(module_information_t));
|
||||
|
||||
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);
|
||||
|
||||
bool forceMenu = true;
|
||||
auto res = getFileContent(AUTOBOOT_CONFIG_PATH);
|
||||
auto autobootIndex = -1;
|
||||
if (res) {
|
||||
DEBUG_FUNCTION_LINE("Got result %s", res->c_str());
|
||||
for (int i = 0; i < environmentDirs.GetFilecount(); i++) {
|
||||
if (environmentDirs.GetFilename(i) == res.value()) {
|
||||
DEBUG_FUNCTION_LINE("Found environment %s from config at index %d", res.value().c_str(), i);
|
||||
autobootIndex = i;
|
||||
environment_path = environmentDirs.GetFilepath(i);
|
||||
forceMenu = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("No config found");
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> environmentPaths;
|
||||
for (int i = 0; i < environmentDirs.GetFilecount(); i++) {
|
||||
environmentPaths[environmentDirs.GetFilename(i)] = environmentDirs.GetFilepath(i);
|
||||
}
|
||||
|
||||
VPADReadError err;
|
||||
VPADStatus vpad_data;
|
||||
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &err);
|
||||
|
||||
uint32_t btn = 0;
|
||||
if (err == VPAD_READ_SUCCESS) {
|
||||
btn = vpad_data.hold | vpad_data.trigger;
|
||||
bool forceMenu = true;
|
||||
auto res = getFileContent(AUTOBOOT_CONFIG_PATH);
|
||||
auto autobootIndex = -1;
|
||||
if (res) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Got result %s", res->c_str());
|
||||
int32_t i = 0;
|
||||
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;
|
||||
environmentPath = val;
|
||||
forceMenu = false;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("No config found");
|
||||
}
|
||||
|
||||
if (forceMenu || (btn & VPAD_BUTTON_X) == VPAD_BUTTON_X) {
|
||||
DEBUG_FUNCTION_LINE("Open menu!");
|
||||
environment_path = EnvironmentSelectionScreen(environmentPaths, autobootIndex);
|
||||
DEBUG_FUNCTION_LINE("Selected %s", environment_path.c_str());
|
||||
InputUtils::Init();
|
||||
|
||||
InputUtils::InputData input = InputUtils::getControllerInput();
|
||||
|
||||
if (forceMenu || ((input.trigger | input.hold) & VPAD_BUTTON_X) == VPAD_BUTTON_X) {
|
||||
shownMenu = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Open menu!");
|
||||
environmentPath = EnvironmentSelectionScreen(environmentPaths, autobootIndex);
|
||||
if (environmentPaths.empty()) {
|
||||
noEnvironmentsFound = true;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Selected %s", environmentPath.c_str());
|
||||
}
|
||||
} else {
|
||||
}
|
||||
InputUtils::DeInit();
|
||||
}
|
||||
|
||||
DirList setupModules(environment_path + "/modules/setup", ".rpx", DirList::Files, 1);
|
||||
setupModules.SortList();
|
||||
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();
|
||||
|
||||
for (int i = 0; i < setupModules.GetFilecount(); i++) {
|
||||
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("Failed to load %s", setupModules.GetFilepath(i));
|
||||
continue;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Loaded module data");
|
||||
auto relocData = moduleData.value()->getRelocationDataList();
|
||||
if (!ElfUtils::doRelocation(relocData, gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) {
|
||||
OSFatal("Relocations failed");
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Relocation done");
|
||||
if (!noEnvironmentsFound) {
|
||||
DirList setupModules(environmentPath + "/modules/setup", ".rpx", DirList::Files, 1);
|
||||
setupModules.SortList();
|
||||
|
||||
for (int i = 0; i < setupModules.GetFilecount(); i++) {
|
||||
//! skip hidden linux and mac files
|
||||
if (setupModules.GetFilename(i)[0] == '.' || setupModules.GetFilename(i)[0] == '_') {
|
||||
DEBUG_FUNCTION_LINE_ERR("Skip file %s", setupModules.GetFilepath(i));
|
||||
continue;
|
||||
}
|
||||
|
||||
LoadAndRunModule(setupModules.GetFilepath(i), environmentPath);
|
||||
}
|
||||
|
||||
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();
|
||||
((int (*)(int, char **)) moduleData.value()->getEntrypoint())(1, arr);
|
||||
DEBUG_FUNCTION_LINE("Back from module");
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Return to Wii U Menu");
|
||||
ProcUIInit(OSSavesDone_ReadyToRelease);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strcmp(argv[i], "void forceDefaultTitleIDToWiiUMenu(void)") == 0) {
|
||||
if ((i + 1) < argc) {
|
||||
i++;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("call forceDefaultTitleIDToWiiUMenu");
|
||||
// clang-format off
|
||||
auto forceDefaultTitleIDToWiiUMenu = (void(*)()) argv[i];
|
||||
// clang-format on
|
||||
forceDefaultTitleIDToWiiUMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Launch menu");
|
||||
SYSLaunchMenu();
|
||||
}
|
||||
|
||||
ProcUIInit(OSSavesDone_ReadyToRelease);
|
||||
@ -195,29 +234,254 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
ProcUIShutdown();
|
||||
|
||||
deinitLogging();
|
||||
__fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define COLOR_WHITE Color(0xffffffff)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 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);
|
||||
uint32_t tvBufferSize = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||
uint32_t drcBufferSize = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||
|
||||
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);
|
||||
|
||||
OSScreenSetBufferEx(SCREEN_TV, screenBuffer);
|
||||
OSScreenSetBufferEx(SCREEN_DRC, screenBuffer + tvBufferSize);
|
||||
@ -226,55 +490,65 @@ 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;
|
||||
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);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
uint32_t i = 0;
|
||||
for (auto const&[key, val]: payloads) {
|
||||
if (i == selected) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, (i == autoBoot) ? COLOR_AUTOBOOT : COLOR_BORDER);
|
||||
}
|
||||
uint32_t i = 0;
|
||||
if (!payloads.empty()) {
|
||||
for (auto const &[key, val] : payloads) {
|
||||
if (i == selected) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, ((int32_t) i == autoBoot) ? COLOR_AUTOBOOT : COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::setFontColor(((int32_t) i == autoBoot) ? COLOR_AUTOBOOT : COLOR_TEXT);
|
||||
DrawUtils::print(16 * 2, index + 8 + 24, key.c_str());
|
||||
index += 42 + 8;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::setFontColor((i == autoBoot) ? COLOR_AUTOBOOT : COLOR_TEXT);
|
||||
DrawUtils::print(16 * 2, index + 8 + 24, key.c_str());
|
||||
index += 42 + 8;
|
||||
i++;
|
||||
DrawUtils::setFontColor(COLOR_RED);
|
||||
const char *noEnvironmentsWarning = "No valid environments found. Press \ue000 to launch the Wii U Menu";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(noEnvironmentsWarning) / 2, SCREEN_HEIGHT / 2, noEnvironmentsWarning, true);
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
@ -283,18 +557,22 @@ 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);
|
||||
DrawUtils::setFontSize(18);
|
||||
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";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(autobootHints) / 2, SCREEN_HEIGHT - 8, autobootHints, true);
|
||||
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/\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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,22 +582,32 @@ std::string EnvironmentSelectionScreen(const std::map<std::string, std::string>
|
||||
|
||||
DrawUtils::deinitFont();
|
||||
|
||||
// Call GX2Init to shut down OSScreen
|
||||
GX2Init(nullptr);
|
||||
|
||||
GX2SetTVEnable(FALSE);
|
||||
GX2SetDRCEnable(FALSE);
|
||||
|
||||
free(screenBuffer);
|
||||
|
||||
if (autoBoot != autobootIndex) {
|
||||
int i = 0;
|
||||
for (auto const&[key, val]: payloads) {
|
||||
if (i == autoBoot) {
|
||||
DEBUG_FUNCTION_LINE("Save config");
|
||||
writeFileContent(AUTOBOOT_CONFIG_PATH, key);
|
||||
break;
|
||||
if (autoBoot == -1) {
|
||||
writeFileContent(AUTOBOOT_CONFIG_PATH, "-1");
|
||||
} else {
|
||||
int i = 0;
|
||||
for (auto const &[key, val] : payloads) {
|
||||
if (i == autoBoot) {
|
||||
DEBUG_FUNCTION_LINE("Save config");
|
||||
writeFileContent(AUTOBOOT_CONFIG_PATH, key);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (auto const&[key, val]: payloads) {
|
||||
uint32_t i = 0;
|
||||
for (auto const &[key, val] : payloads) {
|
||||
if (i == selected) {
|
||||
return val;
|
||||
}
|
||||
|
@ -1,68 +1,53 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018 Maschell
|
||||
*
|
||||
* 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/>.
|
||||
****************************************************************************/
|
||||
* Copyright (C) 2018 Maschell
|
||||
*
|
||||
* 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/>.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
class ImportRPLInformation {
|
||||
|
||||
public:
|
||||
explicit ImportRPLInformation(std::string name, bool isData = false) {
|
||||
this->name = std::move(name);
|
||||
this->_isData = isData;
|
||||
explicit ImportRPLInformation(std::string rawSectionName) {
|
||||
this->name = std::move(rawSectionName);
|
||||
}
|
||||
|
||||
~ImportRPLInformation() = default;
|
||||
|
||||
static std::optional<std::shared_ptr<ImportRPLInformation>> createImportRPLInformation(std::string rawSectionName) {
|
||||
std::string fimport = ".fimport_";
|
||||
std::string dimport = ".dimport_";
|
||||
|
||||
bool data = false;
|
||||
|
||||
std::string rplName;
|
||||
|
||||
if (rawSectionName.size() < fimport.size()) {
|
||||
return std::nullopt;
|
||||
} else if (std::equal(fimport.begin(), fimport.end(), rawSectionName.begin())) {
|
||||
rplName = rawSectionName.substr(fimport.size());
|
||||
} else if (std::equal(dimport.begin(), dimport.end(), rawSectionName.begin())) {
|
||||
rplName = rawSectionName.substr(dimport.size());
|
||||
data = true;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("invalid section name\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::make_shared<ImportRPLInformation>(rplName, data);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getName() const {
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
[[nodiscard]] const char *getRPLName() const {
|
||||
if (name.max_size() < strlen("._import_") + 1) {
|
||||
OSFatal("EnvironmentLoader: Invalid RPLName, is too short to be valid");
|
||||
}
|
||||
return name.c_str() + strlen("._import_");
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isData() const {
|
||||
return _isData;
|
||||
return name.starts_with(".dimport_");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
bool _isData = false;
|
||||
};
|
||||
|
@ -17,11 +17,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "RelocationData.h"
|
||||
#include "utils/MemoryUtils.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "RelocationData.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ModuleData {
|
||||
public:
|
||||
@ -29,15 +30,15 @@ public:
|
||||
|
||||
~ModuleData() = default;
|
||||
|
||||
void setEntrypoint(uint32_t addr) {
|
||||
this->entrypoint = addr;
|
||||
void setEntrypoint(uint32_t address) {
|
||||
this->entrypoint = address;
|
||||
}
|
||||
|
||||
void addRelocationData(const std::shared_ptr<RelocationData> &relocation_data) {
|
||||
relocation_data_list.push_back(relocation_data);
|
||||
void addRelocationData(RelocationData relocation_data) {
|
||||
relocation_data_list.push_back(std::move(relocation_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_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 addr) {
|
||||
this->startAddress = addr;
|
||||
void setTextMemory(ExpHeapMemory &&memory) {
|
||||
mTextMemory = std::move(memory);
|
||||
}
|
||||
|
||||
void setEndAddress(uint32_t _endAddress) {
|
||||
this->endAddress = _endAddress;
|
||||
}
|
||||
|
||||
[[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::shared_ptr<RelocationData>> relocation_data_list;
|
||||
std::vector<RelocationData> relocation_data_list;
|
||||
uint32_t entrypoint = 0;
|
||||
uint32_t startAddress = 0;
|
||||
uint32_t endAddress = 0;
|
||||
ExpHeapMemory mTextMemory;
|
||||
ExpHeapMemory mDataMemory;
|
||||
};
|
||||
|
@ -15,116 +15,145 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <coreinit/cache.h>
|
||||
#include "ModuleDataFactory.h"
|
||||
#include "../utils/FileUtils.h"
|
||||
#include "ElfUtils.h"
|
||||
#include "utils/OnLeavingScope.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/wiiu_zlib.hpp"
|
||||
#include <coreinit/cache.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
using namespace ELFIO;
|
||||
|
||||
std::optional<std::shared_ptr<ModuleData>>
|
||||
ModuleDataFactory::load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampolin_entry_t *trampolin_data, uint32_t trampolin_data_length) {
|
||||
elfio reader;
|
||||
std::shared_ptr<ModuleData> moduleData = std::make_shared<ModuleData>();
|
||||
|
||||
// Load ELF data
|
||||
if (!reader.load(path)) {
|
||||
DEBUG_FUNCTION_LINE("Can't find or process %s", path.c_str());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
auto **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num);
|
||||
|
||||
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) {
|
||||
section *psec = reader.sections[i];
|
||||
if (psec->get_type() == 0x80000002) {
|
||||
ELFIO::section *psec = reader.sections[i];
|
||||
if (psec->get_type() == 0x80000002 || psec->get_name() == ".wut_load_bounds") {
|
||||
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)) {
|
||||
sizeOfModule += psec->get_size() + psec->get_addr_align();
|
||||
}
|
||||
}
|
||||
return sizeOfModule;
|
||||
}
|
||||
|
||||
if (sizeOfModule > maximum_size) {
|
||||
DEBUG_FUNCTION_LINE("Module is too big.");
|
||||
std::optional<std::unique_ptr<ModuleData>>
|
||||
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 {};
|
||||
}
|
||||
|
||||
uint32_t baseOffset = (destination_address_end - sizeOfModule) & 0xFFFFFF00;
|
||||
uint32_t startAddress = baseOffset;
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
|
||||
uint32_t offset_text = baseOffset;
|
||||
uint32_t offset_data = offset_text;
|
||||
auto destinations = make_unique_nothrow<uint8_t *[]>(sec_num);
|
||||
if (!destinations) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array");
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t entrypoint = offset_text + (uint32_t) reader.get_entry() - 0x02000000;
|
||||
|
||||
uint32_t totalSize = 0;
|
||||
uint32_t endAddress = 0;
|
||||
uint32_t text_size = 0;
|
||||
uint32_t data_size = 0;
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[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)) {
|
||||
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();
|
||||
|
||||
totalSize += sectionSize;
|
||||
if (totalSize > maximum_size) {
|
||||
DEBUG_FUNCTION_LINE("Couldn't load setup module because it's too big.");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto address = (uint32_t) psec->get_address();
|
||||
|
||||
destinations[psec->get_index()] = (uint8_t *) baseOffset;
|
||||
|
||||
uint32_t destination = baseOffset + address;
|
||||
auto address = (uint32_t) psec->get_address();
|
||||
if ((address >= 0x02000000) && address < 0x10000000) {
|
||||
destination -= 0x02000000;
|
||||
destinations[psec->get_index()] -= 0x02000000;
|
||||
baseOffset += sectionSize;
|
||||
offset_data += sectionSize;
|
||||
text_size += sectionSize + psec->get_addr_align();
|
||||
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
||||
data_size += sectionSize + psec->get_addr_align();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 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];
|
||||
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)) {
|
||||
uint32_t sectionSize = psec->get_size();
|
||||
auto address = (uint32_t) psec->get_address();
|
||||
|
||||
uint32_t destination = address;
|
||||
|
||||
if ((address >= 0x02000000) && address < 0x10000000) {
|
||||
destination += (uint32_t) text_data.data();
|
||||
destination -= 0x02000000;
|
||||
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) {
|
||||
destination -= 0xC0000000;
|
||||
destinations[psec->get_index()] -= 0xC0000000;
|
||||
DEBUG_FUNCTION_LINE_ERR("Loading section from 0xC0000000 is NOT supported");
|
||||
return std::nullopt;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Unhandled case");
|
||||
free(destinations);
|
||||
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const char *p = reader.sections[i]->get_data();
|
||||
const char *p = psec->get_data();
|
||||
|
||||
if (psec->get_type() == SHT_NOBITS) {
|
||||
DEBUG_FUNCTION_LINE("memset section %s %08X to 0 (%d bytes)", psec->get_name().c_str(), destination, sectionSize);
|
||||
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() == 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") {
|
||||
DEBUG_FUNCTION_LINE("memset %s section. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
|
||||
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
|
||||
} else if (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);
|
||||
@ -132,108 +161,136 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
||||
ELFIO::section *psec = reader.sections[i];
|
||||
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, trampolin_data, trampolin_data_length)) {
|
||||
DEBUG_FUNCTION_LINE("elfLink failed");
|
||||
free(destinations);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto relocationData = getImportRelocationData(reader, destinations);
|
||||
getImportRelocationData(moduleData, reader, destinations.get());
|
||||
|
||||
for (auto const &reloc: relocationData) {
|
||||
moduleData->addRelocationData(reloc);
|
||||
}
|
||||
DCFlushRange((void *) data_data.data(), data_data.size());
|
||||
ICInvalidateRange((void *) text_data.data(), text_data.size());
|
||||
|
||||
DCFlushRange((void *) baseOffset, totalSize);
|
||||
ICInvalidateRange((void *) baseOffset, totalSize);
|
||||
|
||||
free(destinations);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<RelocationData>> ModuleDataFactory::getImportRelocationData(elfio &reader, uint8_t **destinations) {
|
||||
std::vector<std::shared_ptr<RelocationData>> result;
|
||||
std::map<uint32_t, std::string> infoMap;
|
||||
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();
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
auto *psec = reader.sections[i];
|
||||
if (psec->get_type() == 0x80000002) {
|
||||
infoMap[i] = psec->get_name();
|
||||
auto info = make_shared_nothrow<ImportRPLInformation>(psec->get_name());
|
||||
if (!info) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed too allocate ImportRPLInformation");
|
||||
return false;
|
||||
}
|
||||
infoMap[i] = std::move(info);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) {
|
||||
DEBUG_FUNCTION_LINE("Found relocation section %s", psec->get_name().c_str());
|
||||
relocation_section_accessor rel(reader, psec);
|
||||
ELFIO::section *psec = reader.sections[i];
|
||||
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) {
|
||||
Elf64_Addr offset;
|
||||
Elf_Word type;
|
||||
Elf_Sxword addend;
|
||||
ELFIO::Elf_Word symbol = 0;
|
||||
ELFIO::Elf64_Addr offset;
|
||||
ELFIO::Elf_Word type;
|
||||
ELFIO::Elf_Sxword addend;
|
||||
std::string sym_name;
|
||||
Elf64_Addr sym_value;
|
||||
Elf_Half sym_section_index;
|
||||
ELFIO::Elf64_Addr sym_value;
|
||||
|
||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get relocation");
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
// uint32_t adjusted_sym_value = (uint32_t) sym_value;
|
||||
if (infoMap.count(sym_section_index) == 0) {
|
||||
auto adjusted_sym_value = (uint32_t) sym_value;
|
||||
if (adjusted_sym_value < 0xC0000000) {
|
||||
continue;
|
||||
}
|
||||
auto rplInfo = ImportRPLInformation::createImportRPLInformation(infoMap[sym_section_index]);
|
||||
if (!rplInfo) {
|
||||
DEBUG_FUNCTION_LINE("Failed to create import information");
|
||||
break;
|
||||
}
|
||||
|
||||
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("EnvironmentLoader: Relocation is referencing a unknown section.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// When these relocations are performed, we don't need the 0xC0000000 offset anymore.
|
||||
auto relocationData = std::make_shared<RelocationData>(type, offset - 0x02000000, addend, (void *) (destinations[section_index] + 0x02000000), sym_name, rplInfo.value());
|
||||
//relocationData->printInformation();
|
||||
result.push_back(relocationData);
|
||||
moduleData->addRelocationData(RelocationData(type,
|
||||
offset - 0x02000000,
|
||||
addend,
|
||||
(void *) (destinations[section_index]),
|
||||
sym_name,
|
||||
infoMap[sym_section_index]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampolin_entry_t *trampolin_data,
|
||||
uint32_t trampolin_data_length) {
|
||||
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();
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
ELFIO::section *psec = reader.sections[i];
|
||||
if (psec->get_info() == section_index) {
|
||||
DEBUG_FUNCTION_LINE("Found relocation section %s", psec->get_name().c_str());
|
||||
relocation_section_accessor rel(reader, psec);
|
||||
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) {
|
||||
Elf64_Addr offset;
|
||||
Elf_Word type;
|
||||
Elf_Sxword addend;
|
||||
ELFIO::Elf_Word symbol = 0;
|
||||
ELFIO::Elf64_Addr offset;
|
||||
ELFIO::Elf_Word type;
|
||||
ELFIO::Elf_Sxword addend;
|
||||
std::string sym_name;
|
||||
Elf64_Addr sym_value;
|
||||
Elf_Half sym_section_index;
|
||||
ELFIO::Elf64_Addr sym_value;
|
||||
|
||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get relocation");
|
||||
break;
|
||||
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;
|
||||
@ -249,23 +306,31 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
|
||||
} else if (adjusted_sym_value == 0x0) {
|
||||
//
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Unhandled case %08X", adjusted_sym_value);
|
||||
DEBUG_FUNCTION_LINE_ERR("Unhandled case %08X", adjusted_sym_value);
|
||||
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) {
|
||||
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED: %04X", sym_section_index);
|
||||
} 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, trampolin_data, trampolin_data_length, RELOC_TYPE_FIXED)) {
|
||||
DEBUG_FUNCTION_LINE("Link failed");
|
||||
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;
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("done");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -17,20 +17,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "../common/relocation_defines.h"
|
||||
#include "ModuleData.h"
|
||||
#include "elfio/elfio.hpp"
|
||||
#include "../common/relocation_defines.h"
|
||||
#include "utils/MemoryUtils.h"
|
||||
#include "utils/utils.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ModuleDataFactory {
|
||||
public:
|
||||
static std::optional<std::shared_ptr<ModuleData>>
|
||||
load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampolin_entry_t *trampolin_data, uint32_t trampolin_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_trampolin_entry_t *trampolin_data,
|
||||
uint32_t trampolin_data_length);
|
||||
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 std::vector<std::shared_ptr<RelocationData>> getImportRelocationData(ELFIO::elfio &reader, uint8_t **destinations);
|
||||
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, const ELFIO::elfio &reader, uint8_t **destinations);
|
||||
};
|
||||
|
@ -17,20 +17,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "ImportRPLInformation.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
class RelocationData {
|
||||
|
||||
public:
|
||||
RelocationData(char type, size_t offset, int32_t addend, void *destination, std::string name, std::shared_ptr<ImportRPLInformation> rplInfo) : rplInfo(std::move(rplInfo)) {
|
||||
this->type = type;
|
||||
this->offset = offset;
|
||||
this->addend = addend;
|
||||
this->type = type;
|
||||
this->offset = offset;
|
||||
this->addend = addend;
|
||||
this->destination = destination;
|
||||
this->name = std::move(name);
|
||||
this->name = std::move(name);
|
||||
}
|
||||
|
||||
~RelocationData() = default;
|
||||
|
@ -1,55 +1,51 @@
|
||||
#include "DrawUtils.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memory.h>
|
||||
#include <coreinit/screen.h>
|
||||
#include <coreinit/cache.h>
|
||||
#include <cstdlib>
|
||||
#include <png.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
|
||||
// buffer width
|
||||
#define TV_WIDTH 0x500
|
||||
#define TV_WIDTH 0x500
|
||||
#define DRC_WIDTH 0x380
|
||||
|
||||
bool DrawUtils::isBackBuffer;
|
||||
|
||||
uint8_t* DrawUtils::tvBuffer = nullptr;
|
||||
uint32_t DrawUtils::tvSize = 0;
|
||||
uint8_t* DrawUtils::drcBuffer = nullptr;
|
||||
uint32_t DrawUtils::drcSize = 0;
|
||||
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()
|
||||
{
|
||||
uint32_t pixel = *(uint32_t*) tvBuffer;
|
||||
void DrawUtils::beginDraw() {
|
||||
uint32_t pixel = *(uint32_t *) tvBuffer;
|
||||
|
||||
// check which buffer is currently used
|
||||
OSScreenPutPixelEx(SCREEN_TV, 0, 0, 0xABCDEF90);
|
||||
if (*(uint32_t*) tvBuffer == 0xABCDEF90) {
|
||||
if (*(uint32_t *) tvBuffer == 0xABCDEF90) {
|
||||
isBackBuffer = false;
|
||||
} else {
|
||||
isBackBuffer = true;
|
||||
}
|
||||
|
||||
// restore the pixel we used for checking
|
||||
*(uint32_t*) tvBuffer = pixel;
|
||||
*(uint32_t *) tvBuffer = pixel;
|
||||
}
|
||||
|
||||
void DrawUtils::endDraw()
|
||||
{
|
||||
void DrawUtils::endDraw() {
|
||||
// OSScreenFlipBuffersEx already flushes the cache?
|
||||
// DCFlushRange(tvBuffer, tvSize);
|
||||
// DCFlushRange(drcBuffer, drcSize);
|
||||
@ -58,14 +54,12 @@ void DrawUtils::endDraw()
|
||||
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||
}
|
||||
|
||||
void DrawUtils::clear(Color col)
|
||||
{
|
||||
void DrawUtils::clear(Color col) {
|
||||
OSScreenClearBufferEx(SCREEN_TV, col.color);
|
||||
OSScreenClearBufferEx(SCREEN_DRC, col.color);
|
||||
}
|
||||
|
||||
void DrawUtils::drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||
{
|
||||
void DrawUtils::drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
float opacity = a / 255.0f;
|
||||
|
||||
// put pixel in the drc buffer
|
||||
@ -75,42 +69,46 @@ void DrawUtils::drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t
|
||||
i += drcSize / 2;
|
||||
}
|
||||
if (a == 0xFF) {
|
||||
drcBuffer[i ] = r;
|
||||
drcBuffer[i] = r;
|
||||
drcBuffer[i + 1] = g;
|
||||
drcBuffer[i + 2] = b;
|
||||
}
|
||||
else {
|
||||
drcBuffer[i ] = r * opacity + drcBuffer[i ] * (1 - opacity);
|
||||
} else {
|
||||
drcBuffer[i] = r * opacity + drcBuffer[i] * (1 - opacity);
|
||||
drcBuffer[i + 1] = g * opacity + drcBuffer[i + 1] * (1 - opacity);
|
||||
drcBuffer[i + 2] = b * opacity + drcBuffer[i + 2] * (1 - opacity);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (a == 0xFF) {
|
||||
tvBuffer[i ] = r;
|
||||
tvBuffer[i] = r;
|
||||
tvBuffer[i + 1] = g;
|
||||
tvBuffer[i + 2] = b;
|
||||
}
|
||||
else {
|
||||
tvBuffer[i ] = r * opacity + tvBuffer[i ] * (1 - opacity);
|
||||
} else {
|
||||
tvBuffer[i] = r * opacity + tvBuffer[i] * (1 - opacity);
|
||||
tvBuffer[i + 1] = g * opacity + tvBuffer[i + 1] * (1 - opacity);
|
||||
tvBuffer[i + 2] = b * opacity + tvBuffer[i + 2] * (1 - opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawUtils::drawRectFilled(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color col)
|
||||
{
|
||||
void DrawUtils::drawRectFilled(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color col) {
|
||||
for (uint32_t yy = y; yy < y + h; yy++) {
|
||||
for (uint32_t xx = x; xx < x + w; xx++) {
|
||||
drawPixel(xx, yy, col);
|
||||
@ -118,30 +116,28 @@ void DrawUtils::drawRectFilled(uint32_t x, uint32_t y, uint32_t w, uint32_t h, C
|
||||
}
|
||||
}
|
||||
|
||||
void DrawUtils::drawRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t borderSize, Color col)
|
||||
{
|
||||
void DrawUtils::drawRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t borderSize, Color col) {
|
||||
drawRectFilled(x, y, w, borderSize, col);
|
||||
drawRectFilled(x, y + h - borderSize, w, borderSize, col);
|
||||
drawRectFilled(x, y, borderSize, h, col);
|
||||
drawRectFilled(x + w - borderSize, y, borderSize, h, col);
|
||||
}
|
||||
|
||||
void DrawUtils::drawBitmap(uint32_t x, uint32_t y, uint32_t target_width, uint32_t target_height, const uint8_t* data)
|
||||
{
|
||||
if ( data[0] != 'B' || data[1] != 'M' ) {
|
||||
// invalid header
|
||||
return;
|
||||
}
|
||||
void DrawUtils::drawBitmap(uint32_t x, uint32_t y, uint32_t target_width, uint32_t target_height, const uint8_t *data) {
|
||||
if (data[0] != 'B' || data[1] != 'M') {
|
||||
// invalid header
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t dataPos = __builtin_bswap32(*(uint32_t*)&(data[0x0A]));
|
||||
uint32_t width = __builtin_bswap32(*(uint32_t*)&(data[0x12]));
|
||||
uint32_t height = __builtin_bswap32(*(uint32_t*)&(data[0x16]));
|
||||
uint32_t dataPos = __builtin_bswap32(*(uint32_t *) &(data[0x0A]));
|
||||
uint32_t width = __builtin_bswap32(*(uint32_t *) &(data[0x12]));
|
||||
uint32_t height = __builtin_bswap32(*(uint32_t *) &(data[0x16]));
|
||||
|
||||
if (dataPos == 0) {
|
||||
dataPos = 54;
|
||||
}
|
||||
if (dataPos == 0) {
|
||||
dataPos = 54;
|
||||
}
|
||||
|
||||
data += dataPos;
|
||||
data += dataPos;
|
||||
|
||||
// TODO flip image since bitmaps are stored upside down
|
||||
|
||||
@ -153,52 +149,49 @@ void DrawUtils::drawBitmap(uint32_t x, uint32_t y, uint32_t target_width, uint32
|
||||
}
|
||||
}
|
||||
|
||||
static void png_read_data(png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead)
|
||||
{
|
||||
void** data = (void**) png_get_io_ptr(png_ptr);
|
||||
static void png_read_data(png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead) {
|
||||
void **data = (void **) png_get_io_ptr(png_ptr);
|
||||
|
||||
memcpy(outBytes, *data, byteCountToRead);
|
||||
*((uint8_t**) data) += byteCountToRead;
|
||||
*((uint8_t **) data) += byteCountToRead;
|
||||
}
|
||||
|
||||
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) {
|
||||
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, 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;
|
||||
}
|
||||
|
||||
png_set_read_fn(png_ptr, (void*) &data, png_read_data);
|
||||
png_set_read_fn(png_ptr, (void *) &data, png_read_data);
|
||||
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
uint32_t width = 0;
|
||||
uint32_t width = 0;
|
||||
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);
|
||||
if(retval != 1) {
|
||||
int bitDepth = 0;
|
||||
int colorType = -1;
|
||||
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);
|
||||
for (uint32_t yy = y; yy < y + height; yy++) {
|
||||
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) {
|
||||
uint32_t i = (xx - x) * 4;
|
||||
drawPixel(xx, yy, rowData[i], rowData[i + 1], rowData[i + 2], rowData[i + 3]);
|
||||
}
|
||||
else if (colorType == PNG_COLOR_TYPE_RGB) {
|
||||
} else if (colorType == PNG_COLOR_TYPE_RGB) {
|
||||
uint32_t i = (xx - x) * 3;
|
||||
drawPixel(xx, yy, rowData[i], rowData[i + 1], rowData[i + 2], 0xFF);
|
||||
}
|
||||
@ -206,42 +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);
|
||||
void DrawUtils::deinitFont() {
|
||||
sft_freefont(pFont.font);
|
||||
pFont.font = nullptr;
|
||||
pFont = {};
|
||||
}
|
||||
|
||||
void DrawUtils::setFontSize(uint32_t size)
|
||||
{
|
||||
FT_Set_Pixel_Sizes(ft_face, 0, size);
|
||||
void DrawUtils::setFontSize(uint32_t size) {
|
||||
pFont.xScale = size;
|
||||
pFont.yScale = size;
|
||||
SFT_LMetrics metrics;
|
||||
sft_lmetrics(&pFont, &metrics);
|
||||
}
|
||||
|
||||
void DrawUtils::setFontColor(Color col)
|
||||
{
|
||||
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++) {
|
||||
@ -249,66 +252,95 @@ 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];
|
||||
void DrawUtils::print(uint32_t x, uint32_t y, const char *string, bool alignRight) {
|
||||
auto *buffer = new wchar_t[strlen(string) + 1];
|
||||
|
||||
size_t num = mbstowcs(buffer, string, strlen(string));
|
||||
if (num > 0) {
|
||||
buffer[num] = 0;
|
||||
}
|
||||
else {
|
||||
wchar_t* tmp = buffer;
|
||||
while ((*tmp++ = *string++));
|
||||
} else {
|
||||
wchar_t *tmp = buffer;
|
||||
while ((*tmp++ = *string++))
|
||||
;
|
||||
}
|
||||
|
||||
print(x, y, buffer, alignRight);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
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};
|
||||
void DrawUtils::print(uint32_t x, uint32_t y, const wchar_t *string, bool alignRight) {
|
||||
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];
|
||||
uint32_t DrawUtils::getTextWidth(const char *string) {
|
||||
auto *buffer = new wchar_t[strlen(string) + 1];
|
||||
|
||||
size_t num = mbstowcs(buffer, string, strlen(string));
|
||||
if (num > 0) {
|
||||
buffer[num] = 0;
|
||||
}
|
||||
else {
|
||||
wchar_t* tmp = buffer;
|
||||
while ((*tmp++ = *string++));
|
||||
} else {
|
||||
wchar_t *tmp = buffer;
|
||||
while ((*tmp++ = *string++))
|
||||
;
|
||||
}
|
||||
|
||||
uint32_t width = getTextWidth(buffer);
|
||||
@ -317,16 +349,19 @@ uint32_t DrawUtils::getTextWidth(const char* string)
|
||||
return width;
|
||||
}
|
||||
|
||||
uint32_t DrawUtils::getTextWidth(const wchar_t* string)
|
||||
{
|
||||
FT_GlyphSlot slot = ft_face->glyph;
|
||||
uint32_t DrawUtils::getTextWidth(const wchar_t *string) {
|
||||
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;
|
||||
}
|
||||
|
@ -1,20 +1,35 @@
|
||||
#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) {
|
||||
this->color = color;
|
||||
}
|
||||
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
this->r = r; this->g = g; this->b = b; this->a = a;
|
||||
explicit Color(uint32_t color) {
|
||||
this->color = color;
|
||||
}
|
||||
|
||||
uint32_t color;
|
||||
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
this->r = r;
|
||||
this->g = g;
|
||||
this->b = b;
|
||||
this->a = a;
|
||||
}
|
||||
|
||||
uint32_t color{};
|
||||
struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
@ -25,33 +40,47 @@ union Color {
|
||||
|
||||
class DrawUtils {
|
||||
public:
|
||||
static void initBuffers(void* tvBuffer, uint32_t tvSize, void* drcBuffer, uint32_t drcSize);
|
||||
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 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 bool initFont();
|
||||
|
||||
static void 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);
|
||||
|
||||
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:
|
||||
static bool isBackBuffer;
|
||||
|
||||
static uint8_t* tvBuffer;
|
||||
static uint8_t *tvBuffer;
|
||||
static uint32_t tvSize;
|
||||
static uint8_t* drcBuffer;
|
||||
static uint8_t *drcBuffer;
|
||||
static uint32_t drcSize;
|
||||
};
|
||||
|
62
source/utils/FileUtils.cpp
Normal file
62
source/utils/FileUtils.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
|
||||
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)
|
||||
|
||||
int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||
//! always initialze input
|
||||
*inbuffer = NULL;
|
||||
if (size) {
|
||||
*size = 0;
|
||||
}
|
||||
|
||||
int32_t iFd = open(filepath, O_RDONLY);
|
||||
if (iFd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t filesize = lseek(iFd, 0, SEEK_END);
|
||||
lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40));
|
||||
if (buffer == nullptr) {
|
||||
close(iFd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint32_t blocksize = 0x20000;
|
||||
uint32_t done = 0;
|
||||
int32_t readBytes = 0;
|
||||
|
||||
while (done < filesize) {
|
||||
if (done + blocksize > filesize) {
|
||||
blocksize = filesize - done;
|
||||
}
|
||||
readBytes = read(iFd, buffer + done, blocksize);
|
||||
if (readBytes <= 0)
|
||||
break;
|
||||
done += readBytes;
|
||||
}
|
||||
|
||||
::close(iFd);
|
||||
|
||||
if (done != filesize) {
|
||||
free(buffer);
|
||||
buffer = nullptr;
|
||||
return -3;
|
||||
}
|
||||
|
||||
*inbuffer = buffer;
|
||||
|
||||
//! sign is optional input
|
||||
if (size) {
|
||||
*size = filesize;
|
||||
}
|
||||
|
||||
return filesize;
|
||||
}
|
3
source/utils/FileUtils.h
Normal file
3
source/utils/FileUtils.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
|
140
source/utils/InputUtils.cpp
Normal file
140
source/utils/InputUtils.cpp
Normal 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
17
source/utils/InputUtils.h
Normal 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
199
source/utils/MemoryUtils.h
Normal 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;
|
||||
};
|
113
source/utils/OnLeavingScope.h
Normal file
113
source/utils/OnLeavingScope.h
Normal file
@ -0,0 +1,113 @@
|
||||
/**
|
||||
* The contents of this file are based on the article posted at the
|
||||
* following location:
|
||||
*
|
||||
* http://crascit.com/2015/06/03/on-leaving-scope-part-2/
|
||||
*
|
||||
* The material in that article has some commonality with the code made
|
||||
* available as part of Facebook's folly library at:
|
||||
*
|
||||
* https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h
|
||||
*
|
||||
* Furthermore, similar material is currently part of a draft proposal
|
||||
* to the C++ standards committee, referencing the same work by Andrei
|
||||
* Alexandresu that led to the folly implementation. The draft proposal
|
||||
* can be found at:
|
||||
*
|
||||
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189.pdf
|
||||
*
|
||||
* With the above in mind, the content below is made available under
|
||||
* the same license terms as folly to minimize any legal concerns.
|
||||
* Should there be ambiguity over copyright ownership between Facebook
|
||||
* and myself for any material included in this file, it should be
|
||||
* interpreted that Facebook is the copyright owner for the ambiguous
|
||||
* section of code concerned.
|
||||
*
|
||||
* Craig Scott
|
||||
* 3rd June 2015
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* Copyright 2015 Craig Scott
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CRASCIT_ONLEAVINGSCOPE_H
|
||||
#define CRASCIT_ONLEAVINGSCOPE_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
||||
/**
|
||||
* This class is intended to be used only to create a local object on the
|
||||
* stack. It accepts a function object in its constructor and will invoke
|
||||
* that function object in its destructor. The class provides a move
|
||||
* constructor so it can be used with the onLeavingScope factory function,
|
||||
* but it cannot be copied.
|
||||
*
|
||||
* Do no use this function directly, use the onLeavingScope() factory
|
||||
* function instead.
|
||||
*/
|
||||
template<typename Func>
|
||||
class OnLeavingScope {
|
||||
public:
|
||||
// Prevent copying
|
||||
OnLeavingScope(const OnLeavingScope &) = delete;
|
||||
OnLeavingScope &operator=(const OnLeavingScope &) = delete;
|
||||
|
||||
// Allow moving
|
||||
OnLeavingScope(OnLeavingScope &&other) : m_func(std::move(other.m_func)),
|
||||
m_owner(other.m_owner) {
|
||||
other.m_owner = false;
|
||||
}
|
||||
|
||||
OnLeavingScope(const Func &f) : m_func(f),
|
||||
m_owner(true) {
|
||||
}
|
||||
OnLeavingScope(Func &&f) : m_func(std::move(f)),
|
||||
m_owner(true) {
|
||||
}
|
||||
~OnLeavingScope() {
|
||||
if (m_owner)
|
||||
m_func();
|
||||
}
|
||||
|
||||
private:
|
||||
Func m_func;
|
||||
bool m_owner;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Factory function for creating an OnLeavingScope object. It is intended
|
||||
* to be used like so:
|
||||
*
|
||||
* auto cleanup = onLeavingScope(...);
|
||||
*
|
||||
* where the ... could be a lambda function, function object or pointer to
|
||||
* a free function to be invoked when the cleanup object goes out of scope.
|
||||
* The function object must take no function arguments, but can return any
|
||||
* type (the return value is ignored).
|
||||
*
|
||||
* The \a Func template parameter would rarely, if ever, be manually
|
||||
* specified. Normally, it would be deduced automatically by the compiler
|
||||
* from the object passed as the function argument.
|
||||
*/
|
||||
template<typename Func>
|
||||
OnLeavingScope<typename std::decay<Func>::type> onLeavingScope(Func &&f) {
|
||||
return OnLeavingScope<typename std::decay<Func>::type>(std::forward<Func>(f));
|
||||
}
|
||||
|
||||
#endif // CRASCIT_ONLEAVINGSCOPE_H
|
239
source/utils/PairUtils.cpp
Normal file
239
source/utils/PairUtils.cpp
Normal 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
43
source/utils/PairUtils.h
Normal 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{};
|
||||
};
|
@ -23,17 +23,16 @@
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <wut_types.h>
|
||||
#include <stdio.h>
|
||||
#include <utils/StringTools.h>
|
||||
#include <vector>
|
||||
#include <wchar.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
|
||||
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
|
||||
@ -85,7 +84,7 @@ const wchar_t *StringTools::wfmt(const char *format, ...) {
|
||||
static char tmp[512];
|
||||
static wchar_t strWChar[512];
|
||||
strWChar[0] = 0;
|
||||
tmp[0] = 0;
|
||||
tmp[0] = 0;
|
||||
|
||||
if (!format)
|
||||
return (const wchar_t *) strWChar;
|
||||
@ -98,7 +97,7 @@ const wchar_t *StringTools::wfmt(const char *format, ...) {
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
int bt;
|
||||
int32_t strlength = strlen(tmp);
|
||||
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
||||
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
||||
|
||||
if (bt > 0) {
|
||||
strWChar[bt] = 0;
|
||||
@ -112,13 +111,13 @@ const wchar_t *StringTools::wfmt(const char *format, ...) {
|
||||
|
||||
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
tmp[0] = 0;
|
||||
int32_t result = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
str = tmp;
|
||||
result = str.size();
|
||||
}
|
||||
va_end(va);
|
||||
@ -215,7 +214,7 @@ const char *StringTools::FullpathToFilename(const char *path) {
|
||||
if (!path)
|
||||
return path;
|
||||
|
||||
const char *ptr = path;
|
||||
const char *ptr = path;
|
||||
const char *Filename = ptr;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
@ -244,13 +243,13 @@ void StringTools::RemoveDoubleSlashs(std::string &str) {
|
||||
|
||||
// You must free the result if result is non-NULL.
|
||||
char *StringTools::str_replace(char *orig, char *rep, char *with) {
|
||||
char *result; // the return string
|
||||
char *ins; // the next insert point
|
||||
char *tmp; // varies
|
||||
int len_rep; // length of rep (the string to remove)
|
||||
int len_with; // length of with (the string to replace rep with)
|
||||
char *result; // the return string
|
||||
char *ins; // the next insert point
|
||||
char *tmp; // varies
|
||||
int len_rep; // length of rep (the string to remove)
|
||||
int len_with; // length of with (the string to replace rep with)
|
||||
int len_front; // distance between rep and end of last rep
|
||||
int count; // number of replacements
|
||||
int count; // number of replacements
|
||||
|
||||
// sanity checks and initialization
|
||||
if (!orig || !rep)
|
||||
@ -279,10 +278,10 @@ char *StringTools::str_replace(char *orig, char *rep, char *with) {
|
||||
// ins points to the next occurrence of rep in orig
|
||||
// orig points to the remainder of orig after "end of rep"
|
||||
while (count--) {
|
||||
ins = strstr(orig, rep);
|
||||
ins = strstr(orig, rep);
|
||||
len_front = ins - orig;
|
||||
tmp = strncpy(tmp, orig, len_front) + len_front;
|
||||
tmp = strcpy(tmp, with) + len_with;
|
||||
tmp = strncpy(tmp, orig, len_front) + len_front;
|
||||
tmp = strcpy(tmp, with) + len_with;
|
||||
orig += len_front + len_rep; // move to next "end of rep"
|
||||
}
|
||||
strcpy(tmp, orig);
|
||||
|
@ -26,8 +26,8 @@
|
||||
#ifndef __STRING_TOOLS_H
|
||||
#define __STRING_TOOLS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wut_types.h>
|
||||
|
||||
class StringTools {
|
||||
@ -62,4 +62,3 @@ public:
|
||||
};
|
||||
|
||||
#endif /* __STRING_TOOLS_H */
|
||||
|
||||
|
36
source/utils/logger.c
Normal file
36
source/utils/logger.c
Normal file
@ -0,0 +1,36 @@
|
||||
#ifdef DEBUG
|
||||
#include <stdint.h>
|
||||
#include <whb/log_cafe.h>
|
||||
#include <whb/log_module.h>
|
||||
#include <whb/log_udp.h>
|
||||
|
||||
uint32_t moduleLogInit = false;
|
||||
uint32_t cafeLogInit = false;
|
||||
uint32_t udpLogInit = false;
|
||||
#endif // DEBUG
|
||||
|
||||
void initLogging() {
|
||||
#ifdef DEBUG
|
||||
if (!(moduleLogInit = WHBLogModuleInit())) {
|
||||
cafeLogInit = WHBLogCafeInit();
|
||||
udpLogInit = WHBLogUdpInit();
|
||||
}
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
void deinitLogging() {
|
||||
#ifdef DEBUG
|
||||
if (moduleLogInit) {
|
||||
WHBLogModuleDeinit();
|
||||
moduleLogInit = false;
|
||||
}
|
||||
if (cafeLogInit) {
|
||||
WHBLogCafeDeinit();
|
||||
cafeLogInit = false;
|
||||
}
|
||||
if (udpLogInit) {
|
||||
WHBLogUdpDeinit();
|
||||
udpLogInit = false;
|
||||
}
|
||||
#endif // DEBUG
|
||||
}
|
@ -1,34 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <whb/log.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LOG_APP_TYPE "O"
|
||||
#define LOG_APP_NAME "environment_loader"
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS)
|
||||
|
||||
#define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
|
||||
do { \
|
||||
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
#else
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||
#endif
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
|
||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||
} while (0)
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \
|
||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||
} while (0)
|
||||
#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
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
|
||||
|
||||
#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)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
|
||||
|
||||
#endif
|
||||
|
||||
void initLogging();
|
||||
|
||||
void deinitLogging();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
1460
source/utils/schrift.c
Normal file
1460
source/utils/schrift.c
Normal file
File diff suppressed because it is too large
Load Diff
88
source/utils/schrift.h
Normal file
88
source/utils/schrift.h
Normal 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
|
30
source/utils/utils.h
Normal file
30
source/utils/utils.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
template<class T, class... Args>
|
||||
std::unique_ptr<T> make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||
return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename std::unique_ptr<T> make_unique_nothrow(size_t num) noexcept {
|
||||
return std::unique_ptr<T>(new (std::nothrow) std::remove_extent_t<T>[num]());
|
||||
}
|
||||
|
||||
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
118
source/utils/wiiu_zlib.hpp
Normal 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
2
source/version.h
Normal file
@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#define ENVIRONMENT_LOADER_VERSION_EXTRA ""
|
Loading…
x
Reference in New Issue
Block a user