From 06f0d77954b3112a0647ab8de9bf5c31f2fad6bb Mon Sep 17 00:00:00 2001 From: Kevin <6500490+Zeturic@users.noreply.github.com> Date: Sun, 26 Jan 2025 20:06:14 -0500 Subject: [PATCH] implement .definedatalabel, .definearmlabel, and .definethumblabel directives --- Archs/ARM/ArmParser.cpp | 12 ++++++++++++ Commands/CAssemblerLabel.cpp | 12 ++++++------ Commands/CAssemblerLabel.h | 6 ++++-- Parser/DirectivesParser.cpp | 16 ++++++++++++++-- Parser/DirectivesParser.h | 3 +++ Readme.md | 18 ++++++++++++++++++ 6 files changed, 57 insertions(+), 10 deletions(-) diff --git a/Archs/ARM/ArmParser.cpp b/Archs/ARM/ArmParser.cpp index 6ea8fa01..87cae199 100644 --- a/Archs/ARM/ArmParser.cpp +++ b/Archs/ARM/ArmParser.cpp @@ -56,6 +56,16 @@ std::unique_ptr parseDirectivePool(Parser& parser, int flags) return seq; } +std::unique_ptr parseDirectiveDefineArmLabel(Parser& parser, int flags) +{ + return parseDirectiveDefineLabel(parser, flags, false); +} + +std::unique_ptr parseDirectiveDefineThumbLabel(Parser& parser, int flags) +{ + return parseDirectiveDefineLabel(parser, flags, true); +} + const char* msgTemplate = R"( mov r12,r12 b %after% @@ -89,6 +99,8 @@ const DirectiveMap armDirectives = { { ".arm", { &parseDirectiveArm, 0 } }, { ".pool", { &parseDirectivePool, 0 } }, { ".msg", { &parseDirectiveMsg, 0 } }, + { ".definearmlabel", { &parseDirectiveDefineArmLabel, 0 } }, + { ".definethumblabel", { &parseDirectiveDefineThumbLabel, 0 } }, }; std::unique_ptr ArmParser::parseDirective(Parser& parser) diff --git a/Commands/CAssemblerLabel.cpp b/Commands/CAssemblerLabel.cpp index 00938f6e..3ca67dd7 100644 --- a/Commands/CAssemblerLabel.cpp +++ b/Commands/CAssemblerLabel.cpp @@ -7,7 +7,7 @@ #include "Core/SymbolData.h" #include "Util/Util.h" -CAssemblerLabel::CAssemblerLabel(const Identifier& name, const Identifier& originalName) +CAssemblerLabel::CAssemblerLabel(const Identifier& name, const Identifier& originalName, std::optional thumbMode) { this->defined = false; this->label = nullptr; @@ -27,15 +27,15 @@ CAssemblerLabel::CAssemblerLabel(const Identifier& name, const Identifier& origi // does this need to be in validate? if (label->getUpdateInfo()) { - if (&Architecture::current() == &Arm && Arm.GetThumbMode()) - label->setInfo(1); - else + if (&Architecture::current() != &Arm) label->setInfo(0); + else + label->setInfo(thumbMode.value_or(Arm.GetThumbMode())); } } -CAssemblerLabel::CAssemblerLabel(const Identifier& name, const Identifier& originalName, Expression& value) - : CAssemblerLabel(name,originalName) +CAssemblerLabel::CAssemblerLabel(const Identifier& name, const Identifier& originalName, Expression& value, std::optional thumbMode) + : CAssemblerLabel(name,originalName,thumbMode) { labelValue = value; } diff --git a/Commands/CAssemblerLabel.h b/Commands/CAssemblerLabel.h index ea87987c..61121cf3 100644 --- a/Commands/CAssemblerLabel.h +++ b/Commands/CAssemblerLabel.h @@ -4,13 +4,15 @@ #include "Core/Expression.h" #include "Core/Types.h" +#include + class Label; class CAssemblerLabel: public CAssemblerCommand { public: - CAssemblerLabel(const Identifier& name, const Identifier& originalName); - CAssemblerLabel(const Identifier& name, const Identifier& originalName, Expression& value); + CAssemblerLabel(const Identifier& name, const Identifier& originalName, std::optional thumbMode = std::nullopt); + CAssemblerLabel(const Identifier& name, const Identifier& originalName, Expression& value, std::optional thumbMode = std::nullopt); bool Validate(const ValidateState &state) override; void Encode() const override; void writeTempData(TempData& tempData) const override; diff --git a/Parser/DirectivesParser.cpp b/Parser/DirectivesParser.cpp index 66512349..d20d401f 100644 --- a/Parser/DirectivesParser.cpp +++ b/Parser/DirectivesParser.cpp @@ -21,6 +21,7 @@ #include #include +#include std::unique_ptr parseDirectiveOpen(Parser& parser, int flags) { @@ -618,7 +619,7 @@ std::unique_ptr parseDirectiveSym(Parser& parser, int flags) return nullptr; } -std::unique_ptr parseDirectiveDefineLabel(Parser& parser, int flags) +std::unique_ptr parseDirectiveDefineLabel(Parser& parser, int flags, std::optional thumbMode) { const Token& tok = parser.nextToken(); if (tok.type != TokenType::Identifier) @@ -638,7 +639,17 @@ std::unique_ptr parseDirectiveDefineLabel(Parser& parser, int return nullptr; } - return std::make_unique(identifier,Identifier(tok.getOriginalText()),value); + return std::make_unique(identifier,Identifier(tok.getOriginalText()),value,thumbMode); +} + +std::unique_ptr parseDirectiveDefineLabel(Parser& parser, int flags) +{ + return parseDirectiveDefineLabel(parser, flags, std::nullopt); +} + +std::unique_ptr parseDirectiveDefineDataLabel(Parser& parser, int flags) +{ + return parseDirectiveDefineLabel(parser, flags, false); } std::unique_ptr parseDirectiveFunction(Parser& parser, int flags) @@ -832,6 +843,7 @@ const DirectiveMap directives = { { ".sym", { &parseDirectiveSym, 0 } }, { ".definelabel", { &parseDirectiveDefineLabel, 0 } }, + { ".definedatalabel", { &parseDirectiveDefineDataLabel, 0 } }, { ".function", { &parseDirectiveFunction, DIRECTIVE_MANUALSEPARATOR } }, { ".func", { &parseDirectiveFunction, DIRECTIVE_MANUALSEPARATOR } }, diff --git a/Parser/DirectivesParser.h b/Parser/DirectivesParser.h index 2b0f0503..4c2266e9 100644 --- a/Parser/DirectivesParser.h +++ b/Parser/DirectivesParser.h @@ -3,6 +3,7 @@ #include #include #include +#include class CAssemblerCommand; class Parser; @@ -78,3 +79,5 @@ using DirectiveMap = std::unordered_multimap; #define DIRECTIVE_AREA_SHARED 0x00000001 extern const DirectiveMap directives; + +std::unique_ptr parseDirectiveDefineLabel(Parser& parser, int flags, std::optional thumbMode); diff --git a/Readme.md b/Readme.md index 7c774aa8..3cd7b329 100644 --- a/Readme.md +++ b/Readme.md @@ -765,6 +765,13 @@ Defines `Label` with a given value, creating a symbol for it. This can be used s Unlike `Label:`, note that `.definelabel Label,value` is evaluated only once, thus using any expressions that refer to the current state of the assembler (e.g. `org()`, `.`) in combination with `.definelabel` leads to undefined behavior. + +``` +.definedatalabel Label,value +``` + +For architectures other than ARM, this works identically to `.definelabel`, however it can be used to essentially document your intent that the symbol doesn't refer to code. Under ARM architecture, it works identically to `.definearmlabel` (see below). + ### Function labels ``` @@ -895,6 +902,17 @@ ldr r0,=0xFFEEDDCC Inserts a no$gba debug message as described by GBATEK. +### Define labels + +``` +.definearmlabel Label,value +.definethumblabel Label,value +``` + +Identical to `.definelabel`, but explicitly creates an ARM or THUMB label regardless of the current mode. + +Only relevant when linking external code through `.importobj`. ARM uses the least significant bit in addresses to signify whether the code at the target address is using ARM or THUMB mode when setting the program counter through instructions such as `bl` or `blx`. armips automatically remembers the current mode when labels are defined, but this mode may be incorrect when using `.definelabel`. Note that using `.definethumblabel` for data may result in incorrect addresses. + # 6. Macros ## 6.1 Assembler-defined MIPS macros