From 1ed6179ea878003c71b03df49de5363213059afe Mon Sep 17 00:00:00 2001 From: Ahmed Arif Date: Sat, 16 May 2026 23:06:52 +0200 Subject: [PATCH] [ASMPP] Improve MASM translation for Clang IAS (#8981) * [ASMPP] Translate MASM NOT as bitwise complement MASM NOT is a bitwise operator. Emitting C/GAS logical negation changes numeric constant values, for example X87XAM_BAD becomes 0 instead of 0xf800. * [ASMPP] Support additional MASM expression operators Map MASM expression operators through a single helper and add support for shr, eq, ne, lt, le, gt, and ge. This keeps existing and/or/shl/not handling while allowing expressions outside the instruction-token set. * [ASMPP] Translate MASM if expressions Handle plain MASM if through the expression translator so operators like ne are emitted as Clang/GAS syntax. Keep ifdef, ifndef, else, and endif on the existing directive path. * [ASMPP] Handle RIP-relative numeric offsets Keep constant +/- offsets before the emitted [rip] suffix so Clang IAS sees forms like symbol+4[rip] instead of the invalid symbol[rip]+4. * [ASMPP] Balance FRAME procedure unwind directives Clang IAS rejects .func/.endfunc and requires .seh_endproc or .cfi_endproc to match an active frame. Track whether each PROC line contains FRAME, including forms such as PROC PRIVATE FRAME, and emit the closing unwind directive only for framed procedures. * [ASMPP] Simplify whitespace skipping for RIP offsets --- sdk/tools/asmpp/asmpp.cpp | 174 ++++++++++++++++++++++++++++++++------ 1 file changed, 146 insertions(+), 28 deletions(-) diff --git a/sdk/tools/asmpp/asmpp.cpp b/sdk/tools/asmpp/asmpp.cpp index bd74fcfd444..35ef626209b 100644 --- a/sdk/tools/asmpp/asmpp.cpp +++ b/sdk/tools/asmpp/asmpp.cpp @@ -298,6 +298,8 @@ unsigned int g_label_number = 0; bool g_processing_jmp = false; +vector g_proc_frame_stack; + enum class IDTYPE { Memory, @@ -358,6 +360,27 @@ iequals(const string &a, const string &b) return true; } +const char* +get_expression_operator(const string &op) +{ + const struct + { + const char* masm; + const char* gas; + } operators[] = { + {"and", "&"}, {"or", "|"}, {"shl", "<<"}, {"shr", ">>"}, {"not", "~"}, + {"eq", "=="}, {"ne", "!="}, {"lt", "<"}, {"le", "<="}, {"gt", ">"}, {"ge", ">="}, + }; + + for (const auto& entry : operators) + { + if (iequals(op, entry.masm)) + return entry.gas; + } + + return nullptr; +} + Token get_expected_token(Token&& tok, TOKEN_TYPE type) { @@ -500,43 +523,45 @@ translate_expression(TokenList &tokens, size_t index, const vector ¯ break; case TOKEN_TYPE::Instruction: - if (iequals(tok.str(), "and")) - { - printf("&"); - index += 1; - } - else if (iequals(tok.str(), "or")) - { - printf("|"); - index += 1; - } - else if (iequals(tok.str(), "shl")) - { - printf("<<"); - index += 1; - } - else if (iequals(tok.str(), "not")) - { - printf("!"); - index += 1; - } - else + { + const char* op = get_expression_operator(tok.str()); + if (!op) { throw "Invalid expression"; } + printf("%s", op); + index += 1; break; + } case TOKEN_TYPE::Operator: if (tok.str() == ",") { return index; } + index = translate_token(tokens, index, macro_params); + break; + + case TOKEN_TYPE::Identifier: + { + const char* op = get_expression_operator(tok.str()); + if (op) + { + printf("%s", op); + index += 1; + } + else + { + index = translate_token(tokens, index, macro_params); + } + break; + } + case TOKEN_TYPE::WhiteSpace: case TOKEN_TYPE::BraceOpen: case TOKEN_TYPE::BraceClose: case TOKEN_TYPE::DecNumber: case TOKEN_TYPE::HexNumber: - case TOKEN_TYPE::Identifier: index = translate_token(tokens, index, macro_params); break; @@ -581,6 +606,55 @@ size_t translate_mem_ref(TokenList& tokens, size_t index, const vector& return index; } +static +bool +is_number_token(const Token& tok) +{ + return ((tok.type() == TOKEN_TYPE::DecNumber) || + (tok.type() == TOKEN_TYPE::HexNumber)); +} + +static +size_t +skip_whitespace(TokenList& tokens, size_t index) +{ + if ((index < tokens.size()) && + (tokens[index].type() == TOKEN_TYPE::WhiteSpace)) + { + index++; + } + + return index; +} + +static +size_t +translate_rip_relative_offset(TokenList& tokens, size_t index, const vector& macro_params) +{ + size_t operatorIndex = skip_whitespace(tokens, index); + if ((operatorIndex == tokens.size()) || + (tokens[operatorIndex].type() != TOKEN_TYPE::Operator) || + ((tokens[operatorIndex].str() != "+") && + (tokens[operatorIndex].str() != "-"))) + { + return index; + } + + size_t numberIndex = skip_whitespace(tokens, operatorIndex + 1); + if ((numberIndex == tokens.size()) || + !is_number_token(tokens[numberIndex])) + { + return index; + } + + while (index <= numberIndex) + { + index = translate_token(tokens, index, macro_params); + } + + return index; +} + size_t translate_instruction_param(TokenList& tokens, size_t index, const vector& macro_params) { switch (tokens[index].type()) @@ -622,6 +696,7 @@ size_t translate_instruction_param(TokenList& tokens, size_t index, const vector !is_string_in_list(macro_params, tok.str()) && !g_processing_jmp) { + index = translate_rip_relative_offset(tokens, index, macro_params); printf("[rip]"); } break; @@ -934,6 +1009,31 @@ translate_record(TokenList &tokens, size_t index, const vector ¯o_pa return index; } +static +bool +find_proc_frame(TokenList& tokens, size_t index, size_t& frameEndIndex) +{ + while (index < tokens.size()) + { + Token tok = tokens[index]; + if ((tok.type() == TOKEN_TYPE::NewLine) || + (tok.type() == TOKEN_TYPE::Comment)) + { + return false; + } + + if (tok.type() == TOKEN_TYPE::KW_FRAME) + { + frameEndIndex = index + 1; + return true; + } + + index++; + } + + return false; +} + size_t translate_identifier_construct(TokenList& tokens, size_t index, const vector ¯o_params) { @@ -989,19 +1089,21 @@ translate_identifier_construct(TokenList& tokens, size_t index, const vector ¯o } case TOKEN_TYPE::KW_if: + printf("."); + return translate_expression(tokens, index, macro_params); + case TOKEN_TYPE::KW_ifdef: case TOKEN_TYPE::KW_ifndef: case TOKEN_TYPE::KW_else: case TOKEN_TYPE::KW_endif: - // TODO: handle parameter differences between "if" and ".if" etc. printf("."); return complete_line(tokens, index, macro_params);