Assigning support variables (such as those for original segments and the
ELF header helper) external linkage and giving them a name prevents the
optimizer from dropping them.
* Create 3 constant global variables (`phdr_address`, `e_phentsize` and
`e_phnum`) in the IR which will be used to populate the auxiliary
vectors at run-time.
* Update compile options for `support.c` to ignore useless warnings and
enable debug information
* Implement in `support.c` some functions required by QEMU run-time and
other cleanups to make it compatible with programs translated from
`_start`, not `root`
* Implement in `support.c` the `prepare_stack` function, which
initializes the base of the stack with environment variables,
arguments and auxiliary vectors
* Improve syscall support
If EarlyCSE didn't produce any new code pointer, we use
GlobalValueNumbering which usually leads to better results, in
particular if we remove `newpc` markers and if it can make use of alias
information, which we introduce to let the compiler know that
loads/stores to the CPU state will never alias loads/stores to normal
memory.
* Before generating any load/store instruction mark it with the
appropriate aliasing information.
* Update `JumpTargetManager::harvest` to run GVN
* Move the `Visited` set of `JumpTargetsFromConstantsPass` in
`JumpTargetManager`, even if currently we clear it at each invocation
of the pass
Some hand crafted assembly code perform a PC-relative jump of an
non-statically known amount. This patch introduces a simple hack to
handle such a situation by simply detecting it and marking as potential
jump targets all the instructions to come until the next jump.
This is implemented by the `JumpTargetManager::handleSumJump` and
`isSumJump` functions.
This commit also introduces a new implementation of `getNextPC` not
requiring the dominator tree.
* Ignore support functions (i.e. everything outside the `root` function)
* Update DWARF version to 4
* Update subrprogram creation interface to LLVM 3.8
The logic to implement harvesting of new code pointers when we're out of
them during translation, has been moved to `JumpTargetManager`. Its
interface has also been reduced and some logging has been introduced.
At the current stage, if there's nothing to `peek`, we first give a shot
of `SROA` and `TranslateDirectBranchesPass`, and then, if nothing came
out, we go for `EarlyCSE` and `JumpTargetsFromConstantsPass`.
Introduce an unreachable instruction after each emitted call to
`exit_tb` to terminate properly basic blocks. This patch also removes it
when appropropriate (i.e. in `TranslateDirectBranchesPass` and
`JumpTargetManager::translateIndirectJumps`).
Instead of taking note of the executable ranges exclusively, keep track
of all the segments in `CodeGenerator`. `JumpTargetManager` instead will
keep track of executable areas only.
* Introduce the `SegmentInfo` struct, which simply holds essential
information about the segment such as start and end address,
permissions and a reference to the global variable holding its content.
* Update `CodeGenerator` to keep a vector of `SegmentInfo`.
* `JumpTargetManager`: polish the constructor and make it take the vector
of `SegmentInfo`, from which the executable ranges are then extracted.
Detect simplest cases of writes to the program counter while they're
being translated. This way, we avoid running expensive passes to collect
straightforward jump targets.
Note: if the PC-write value is the current PC, ignore it. Splitting the
basic block being created is problematic.
* Let `InstructionTranslator::newInstruction` return also the PC.
* `InstructionTranslator::translate`: make it aware of the current PC,
and make it abort in case of error and return a boolean to indicate
whether the translation should proceed or not.
* Simplify the fetch of a new address to translate.
* Let `InstructionTranslator::translateOpcode` return an error condition
in case of failure, instead of asserting.
* Don't start exploration from `VirtualAddress` but just add it as a
block to explore. Then start the translation with
`JumpTargetManager::peek` as usual.
* Remove the unreachable instruction we were using as a delimiter to
create new local variables, since it make the module invalid. Use the
fake branch to the dispatcher instead.
`JumpTargetManager::getPrevPCWrite` used to assert in case a write to the
PC is not immediately found before an `exit_tb`. Relax this constraint.
In the future we might re-introduce it if we handle a couple of common
cases.
In variable-length encoding architectures, sometimes you might have one
instruction containing another one. This is not a problem until you get
the next one, which would be translated twice, in fact, it's not at the
beginning of a basic block and the current mechanism to detect already
translated code does not handle it.
This patch makes `JumpTargetManager::newPC` check the whole map of the
translated instructions. This might have to be improved in the future.
* s/`importGlobalData`/`parseELF`/
* Save the entry point specified in the ELF header, which will be used
if the user doesn't provide an address.
* Let parse `parseELF` take care of informing libtinycode about what
has to be mmap'd and where.
* Remove some support scripts used during testing, now no longer
necessary.
* Various cleanups
* Introduce the `JumpTargetsFromConstantsPass` pass, which goes through
all the unvisited basic blocks looking for constants and trying to feed
them to `JumpTargetManager`, which will decide if they are code
pointers or not.
* To make life of `JumpTargetsFromConstantsPass` easier run
`EarlyCSEPass` before it, which is particularly useful to make explicit
constants that some architectures materialize in two steps (high and
low part).
* Remove the fake fallthrough workaround in `TranslateDirectBranchesPass`
which was used to register for exploration basic blocks after a direct
jump, which was necessary due to the fact that return instructions are
indirect jumps and were losing the basic blocks after function calls.
This is no longer necessary thanks to `JumpTargetsFromConstantsPass`.
Now, in `JumpTargetManager::getBlockAt`, before registering a new PC for
translation we check that the corresponding address was actually
contained in a segment marked as executable in the original binary. This
prevents translation of data, which is a problem in particular when we
will start to harvest possible code pointers from global data or
constants found in the code
* Register in `CodeGenerator::ExecutableRanges` address ranges which
contained executable code in the input ELF.
* In `JumpTargetManager::getBlockAt` check if the given PC was actually
in an executable memory area, and assert or return `nullptr` depending
on the `Try` parameter.
Before this patch the dispatcher area was created all at once at a final
stage, however it's useful also while translating, since it keeps all the
code reachable, which is particularly important to be able to build a
exhaustive dominator tree.
* Create the dispatcher area when a new instance of `JumpTargetManager`
is created.
* Create a fake conditional branch to the dispatcher at the beginning of
the `root` function.
* Incrementally build the dispatcher's switch case in
`JumpTargetManager::getBlockAt`.
In `TranslateDirectBranchesPass::getNextPC` we were using a normal
iterator backward with a faulty exit condition that lead us to skip the
first instruction in a basic block.
This patch implements a proper solution: use `reverse_iterator`.
Fixed a bug which lead to remove from the list of unexplored basic
blocks the wrong one while calling `JumpTargetManager::newPC` from
`InstructionTranslator::newInstruction`. This bug was due to the fact
that we were reading the address of the basic block associated with a PC
*after* erasing it from the `std::vector`.
* Use `llvm::object` framework to obtain useful information from the ELF
binary such as pointer size and endianess.
* Introduce `CodeGenerator::importGlobalData`: import global (read-only
and writeable data) from the input binary directly into the generated
module.
* Introduce the `--linking-info` parameter: path to a CSV file where
sections containing global data extracted from the input binary are
listed with their name, start and end address.
* Expand the `Architecture` class with constructors and support accessor
methods.