| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
| |
This magic comment allows for the definition of segments that are fixed
and for which references are always safe. This goes in tandem with the
asan:safe comment, which can then be used more sporadically.
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>
|
| |
|
|
|
|
|
| |
And also adjust the code so the clippy from the 2024 edition is fine
with it.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
| |
This is basically the same as "asan:ignore", but to the programmer it
will sound less weird on non-ASAN uses.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Imagine the following scenario:
lda #.lobyte(@address + 1)
Here we have an immediate which comes from the .lobyte call. That being
said, since this is using the '#' symbol, we look ahead after noticing
it just in case we need to disambiguate some scenarios. When a
parenthesis is found, in extract_paren_expression() we temporarily
discard the looking ahead status as expressions inside of parenthesis
are no longer affected by any hypothetical external ambiguity. This,
though, was not being done in parse_arguments(), which is the function
that would be called in the above scenario.
Hence, ensure that we temporarily decrease the look ahead status for the
inner arguments, and then increase it back when we are done. This way,
when the parser finds '@address', it will no longer go the "we have
found a 'value', refrain from ambiguities and return early" route, and
it will check for any binary expression.
Note that all this dance actually applied here, as binary operations are
a source of ambiguities, and the look ahead mechanism was brought about
because of these kinds of expressions. Hence, it's not like the look
ahead mechanism is troublesome in on itself, we just missed the special
handling on this specific scenario.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
This statement allows programmers to reserve a memory range for the
stack. This is useful to reserve a memory region which is not attached
to any variable, and:
1. It is a way to safely reserve space on the $0100 page.
2. The --stats/--write-info flags will be able to add up the memory
space reserved for the stack.
3. Future tooling might be able to use this value as a way to detect
stack overflows.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
| |
In this case it was silently letting it go in the hopes that the
assembler would catch it, but it's better to just handle it in the
parser and give a proper error instead of complicating the assembler a
bit more.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Implementing it as a control statement has the bad thing that it's
impossible to be compatible with other assemblers such as ca65, as you
cannot create dummy control statements or something like that in
there. Instead of that, we define it with the special underscores which
are still valid for identifiers, and give a "compiler-specific thingie"
flair to it.
This also has the benefit that the parser can be a bit more strict.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The way macro expansions work is that the evaluated bundles replace the
current node, but this throws away the context of the line, the source,
etc. from the original line of code.
Add a stack that is pushed/popped when expanding macros, and are then
cloned for each pending node and error. This way, errors have full
context of the original code and can display backtraces for macro
expansion.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This way, if you define a constant like:
MY_BUFFER_LEN_IN_BYTES = $10
You can then declare your buffer like so:
zp_buffer = $00 ; asan:reserve MY_BUFFER_LEN_IN_BYTES
And then further in the code you can rely on just using the constant for
bound checking, and then the address sanitizer will check on bound
checks via static analysis as well.
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
|
|
|
| |
This is the next step coming from commit d64ed8c531b0 ("Do not allow
empty strings on .include").
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
|
| |
|
|
| |
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>
|
| |
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
| |
These are special directives that happen on comments, and hence this
parser will no longer simply ignore comments.
This feature is not used by the assembler, but following commits should
build up address sanitizer strategies from it.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Arguments can be put inside of enclosing parenthesis, but the parser was
assuming that if an opening paren was found when parsing the first
argument on an argument list, then that was all it was needed to be
parsed. This though conflicts with situations like:
.byte ($01 << 2) | ($01 << 1)
In this case, the parser would have ignored everything past the first
closing paren.
This commit provides a fix in which if an operation is found past the
first enclosing parenthesis, then this assumption is discarded in favor
of a parenthesis being used for disambiguating on an
arithmetical/logical expression.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
This dependency was easily avoidable and it brought with it a lot of
inner dependencies of its own, most notably 'zerocopy-derive', which
forbid us to compile the affected programs purely statically.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
If the programmer only wrote a single special character for an
identifier, then we will consider it empty to avoid shenanigans.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
In fact, they were always allowed, but they were in kind of grey area,
as they could be defined but not used, and sometimes they could be used
in the middle of identifiers, which was unexpected.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
There were certain situations in which syntax ambiguity could arise. For
example, the parser as it stood could treat a valid expression such as
'lda #$80 >> 2' in an unexpected 'lda #$(80 >> 2)'.
This is of course bad, and it came from the fact that literals don't
have enclosing characters, and white spaces are not enough to provide
disambiguation in some cases. Because of this fact, the parser now has a
"look ahead" capability similar to many other parsers, and it's applied
for now only to literals. This looking ahead actually honors
parenthesis, so these can be added if the programmer wants to
explicitely disambiguate an expression.
This involved quite the heavy lifting, and some functions like
'parse_expression_with_identifier' had to be removed with the rewrite.
This had the side effect of having (hopefully) more sane functions all
around, and the parser also has a better capability to differentiate
between regular Values and Calls.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
| |
This is in preparation to some heavy lifting that is to be done to the
parser so it more properly handles nested expressions, but in general
it's a good idea to have some limits to functions that expect to be
called recursively quite heavily.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
Instead of making up a list of characters that end an identifier, do the
other way around since it's far less cumbersome and it prevents from
silly bugs such as "var+1" being considered a single identifier.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
They are just synonyms for ".if .defined" and ".if !.defined"
respectively.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
Allow for expressions that evaluate to a boolean expression. This in
turn mean that the value is just set to 0 or 1 depending on the given
condition. As with other assemblers, only a value of 0 evaluates to 0,
and others go to 1. So, something like "1 && 2" evaluates to 1 even if
it doesn't make much sense at first glance (as an assembler we just
assume that the programmer knows what it's doing).
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
As with e27a1593c8d8 ("Allow semicolons inside of strings"), the parser
was too naive and regarded any '=' operator as part of an assignment,
despite that it could be art of string literal.
Luckily the fix was already done inside of the parsing of assignments,
we just needed to move it up.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The parser was too naive and assumed that a semicolon immediately
implied an inline comment, and that might not just be the case as it is
with string literals.
Hence, the end of each semantic line has to consider not only whether
there is an inline comment, but also if a string literal is being used
and whether it surrounds or not the given semicolon.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
Some control statements (e.g. '.incbin', '.asciiz') only require a
double-quoted string as an argument. In fact, for these functions
there's only one argument required, which is this string one. Given this
fact, the parsing on these functions don't have to go through
the (expensive) general argument parsing function, and they can simply
assume that a double-quoted string will be provided.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
| |
Some operators like '<' and '<<' could be mistakingly be treated as the
other. Let's remove this ambiguity when checking for unary operators.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
The other cases in which fetching an "identifier" is not needed were
starting to pile up. Hence, split them into separate functions and allow
'parse_expression' to be more simple.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
| |
Before this it was left to the `parse_identifier` to figure things out,
but this was prone to silly errors like "a: b", in which it would
mistake it as the start of a label. Instead of any of this, just consume
a string literal if it has been detected.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
| |
Also remove some pending TODOs.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
| |
Also documented the struct as it is exported.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
They started with good intentions, but in the end they were all pretty
much alike. Hence, it makes sense to simplify everything and provide a
single struct.
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>
|
| |
|
|
|
|
|
|
|
|
| |
In bad314e1cfbf ("Prevent numeric literals from having spaces") it was
added already the restriction on not having whitespace characters in
literal expressions. Here we go a step further and we more explicitely
limit which symbol combinations can go into a literal declaration (e.g.
"#$2" is valid but "##2" is not).
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
It has been found that having literals like "# 20" can potentially be
troublesome and even introduce crashes. Hence, as it's done in other
assemblers, disallow this kind of syntax.
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>
|
| |
|
|
|
|
|
|
|
| |
The parsing of control statements have become more complex since the
introduction of block bodies in 1f8a6becc7cd ("parser: Implement block
bodies"); so it makes sense to move it into its own thing and keep
`parse_statement` more clear.
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>
|
| |
|
|
|
|
|
|
|
|
| |
These are bodies which are the right node of some proc controls. This
way the parser comes back to sanity for statements like .macro and the
likes, and behaves more like a usual parser. This was not done in the
past because I thought things could have been simpler this way, but it
ended up making the assembler way more complicated that it needed to.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
| |
This includes support for both binary and unary operators. Not all of
them as listed by ca65 have been moved in. Let's do that whenever it
make sense on each case.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
| |
Some expressions might be enclosed with parenthesis in order to avoid
ambiguations when evaluating them. Account for this on the parser when
parsing expressions. Note that this is strictly only on the
`parse_expression` function; statements or other top level constructs
cannot be enclosed inside of parenthesis.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
If the given char literal was not an ASCII one, there was the chance for
the character iterator to mess things up. Hence, when checking the
closing single quote, it might encounter a None value.
This is simply mitigated my moving the check of ASCII alphanumeric
before checking for the closing quote.
Fixes: b1623996c76f ("Add support for character literals")
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|
| |
|
|
| |
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
|