| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Some segments, like the 'vectors' one, will reference code that is
outside of its mapping. But in some other configurations, segments
cannot make these cross-mapping references so happily. Imagine:
.segment "SWAPPABLE"
.proc foo
rts
.endproc
.segment "FIXED"
jsr foo
Here the assembler will properly detect the address of 'foo' in the
context of the 'SWAPPABLE' segment. But what this assembler doesn't know
is that this segment is swappable (e.g. UNROM chip). Hence, if the bank
being mapped right now is not the one containing the 'SWAPPABLE'
segment, then the address computed for 'foo' and used in that 'jsr'
instruction will point to something else entirely. This would be similar
to a use-after-free bug.
This is something that can only be inspected at runtime, and so the
assembler cannot be of much help here. Hence, this commit adds a warning
so the programmer can understand the potentially dangerous operation.
All of that being said, this commit also adds support for "asan:safe" or
"check:safe", which is a magic comment that the programmer can write to
re-assure the assembler that this operation is fine (e.g. there is a
guarantee that the mapped bank is that one we are expecting). Hence, the
code above could now be written like so:
jsr foo ; check:safe
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The enum type for macro arguments has been adjusted so it accepts a
String. This is then used to store the name of the macro for this
argument.
This is a bit of a circlejerk, but in the end it stems from the fact
that macro arguments were sort of a hack defined ad-hoc each time they
were needed. That being said, if we want to report macro arguments being
unused, we need to reference the actual macro definition, not the macro
call.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Macro arguments get tampered with every time a new call has to be
bundled. Deep down this is done by cloning the underlying object, but
this resets any increase on the 'accessed' member, giving always the
impression that macro arguments are never accessed. Fix this by at least
preserving this member when cloning a macro argument.
Note that this is neither the most elegant solution, and probably not
the most correct. As in, it will probably get into a non-precise count
after some calls. But at least it will be a non-zero value, which is
more than enough to what this is actually used for.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When warning users on unused objects (e.g. variables, proc's), we have
to pick up the source of origin for this warning. In places where the
original PNode is not available, then we go with the last source we have
at hand, as that's the usual way to go (i.e. the error occurred at the
current source/context).
That being said, for unused objects that's not desirable, because we
might otherwise claim the error to happen on the file we first
targetted, but it's way more useful to understand where the object was
defined.
Hence, when defining a variable, address or proc, let's actually store
the PNode associated with it as well. This way the checker can hopefully
get the source from this PNode and be more clear to the user.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
| |
This is much clearer to the programmer.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
| |
This is actually an expansion from asan(), but it also checks for stuff
that goes outside of the realm of address sanitation. In this aspect,
asan() has been integrated inside of the new check() function.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We cannot safely detect all scenarios in which there is dead code, but
we can safely do it for .proc's. Even if they are not called directly,
they might be referenced via jump tables and shenanigans like that. Long
story short, if you are not referencing a .proc in any meaningful way,
then we have dead code.
A pattern could also be given in which a function that was too long has
been splitted into smaller functions which are not called
directly. This is, in my opinion, an anti-pattern (as we generally
expect an rts or a jmp from .proc's), and anyways can be avoided via the
use of __fallthrough__ if the programmer is really set to write this
kind of code.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
| |
This is applied whenever a given memory range name is not under the
global context. The end result is that scopes will be shown into the
memory.txt file when using '--write-info'.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
| |
These are usually capitalized, and thus they are not going to be
following the usual zp_/m_/wr_ pattern.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
By how we define scopes, we needed an internal name for the global
scope. All the way back to my first commit 587dd5bb8036 ("Initial
commit"), I simply picked "Global". That is troublesome, as it can
easily be typed by a human. If a programmer writes a scope with "global"
definitions via this scope, this can be messed up with nasm's internal
Global scope.
Change that to a more obscure name for this internal global scope. If a
programmer is so dead from the inside that wants to have a scope named
like that, so be it.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Sometimes performing some 'jmp'/'jsr' can be quite pointless, and the
programmer might not be fully aware of this because of the layout of the
code. Imagine:
.proc foo
;; code
jmp bar
.endproc
;; Documentation, comments, extra space, etc.
.proc bar
;; whatever
.endproc
The 'jmp' in the code above tries to perform a call stack optimization,
but it's actually not needed because the next instruction after 'jmp' is
the one inside of 'bar', but that's obfuscated because of the layout.
In these sort of cases (and also for 'jsr' and branches) warn the
programmer about it so it can remove that instruction.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
| |
This allows for reserving memory regions which go outside of the page
boundary.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
This is the initial support for both directives for the address
sanitizer. Note that asan:weak has been moved into asan:ignore, which is
not exactly the same but for now it should suffice.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
| |
This allows the `evaluate_variable` to pull from it in the crunching
stage so to evaluate the original node in cases like macro expansion,
where the connection between the macro argument and the original caller
might have been lost.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
When calling `force_context_switch` the stack was mindlessly pushing the
given name without taking into consideration how scopes are to be laid
out. This made some variables/addresses that were previously preserved
no longer reachable when crunching pending nodes.
This patch also makes `force_context_switch` reset the stack before
doing anything at all, which means that `force_context_pop` was no
longer relevant.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
This needed some heavy lifting when it comes to how files were located.
This means that statements like .include/.incbin now take into
consideration a new list made out of SourceInfo, which holds enough
information to translate from which file a node comes from. This has
also been added into errors, so they are more informative on what went
wrong.
In order to tests this, besides all the regular unit tests, a new e2e
test has been added.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is a control statement which acts similarly as .proc/.macro/.scope,
in which an inner block is allocated for it. Hence, all the previous
work from 1f8a6becc7cd ("parser: Implement block bodies") and
ec8b709fa24c ("Implement block bodies inside of the assembler") make
this one out possible, as .repeat statements don't have an identifier
that can be used for hashing.
From the parser perspective this introduction raises two new things.
First of all this control statement also needed a differentiation
between the amount of required arguments, and the allowed ones, since
there is a second optional argument to it. And second, even the
identifier is not given, we have to generate one so to add a context for
it. This was at first not needed, but introducing .repeat-only variables
means that we have to have inner contexts which need to be named somehow
so we can retrieve the context later when picking up the value for them
again.
This last thing brought the need for a new dependency: rand. This is
used to generate a random string to identify the .repeat block.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It is not safe to store a node index for macros since the list of nodes
that is passed down during assembly might change depending on whether an
inner block is being evaluated. Hence, the previous implementation would
break on a simple macro call inside of a .proc.
This also raised some concerns on the design around the API, since the
lifetime of references for internal assembler data needed an explicit
lifetime now, and as a side-effect functions like `assemble` had to be
moved out of the inner impl Assembler. This is in retrospect also a
better design choice.
Fixes: ec8b709fa24c ("Implement block bodies inside of the assembler").
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
Following 1f8a6becc7cd ("parser: Implement block bodies"), the support
for the new way of managing block bodies have also been added into the
assembler.
There are still some things to iron out, but they will be fixed in later
commits.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
If a given variable cannot be found on the current scope, attempt to go
up the context hierarchy to find it.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
Up until now defining a proc only involved pushing/popping the context.
Here we also allow it to create a label so it can be referenced by
instructions like jsr.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
| |
Fixes: 03dae41b2ec2 ("Prevent addresses which are out of bounds")
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
| |
In some bad scenarios addresses might be pointing out of bounds (e.g. a
reference further than 0xFFFF). This has to be avoided and through fuzzy
testing we even got Rust panics for out of bounds u16 arithmetic. Hence,
just go through usize for the actual computation and check with
u16::MAX.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
|
|
There was a big missunderstanding on how things were to be laid out in
the end file, and so it was needed to create a proper understanding on
what's a Mapping and what's a Segment. These turned out to be
fundamental concepts that I failed to grok up until this commit.
Hence, this commit re-arranges completely how variables and labels are
stored in the Context, and how these objects can then be translated into
bundles that can be spit out to the caller.
This commit, besides introducing the new Mapping struct, also introduced
a more general Object, which abstracts things from the Bundle struct,
and allows us to pass certain metadata about the bundle at hand.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|