From df9ddb1e4eb144f74157e08b86e7b8c50d0d225c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 19 Mar 2024 19:16:24 +0100 Subject: [PATCH 01/11] printf the hell out of it, ongoing --- src/gas/gas.cc | 10 ++++++++++ src/gas/gas.hh | 1 - src/gas/gas.windows.cc | 21 +++++++++++++++++---- src/gas/main.cc | 6 ++++-- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/gas/gas.cc b/src/gas/gas.cc index 7efd933..6c0bc6d 100644 --- a/src/gas/gas.cc +++ b/src/gas/gas.cc @@ -58,7 +58,9 @@ int Gas::usage (bool is_error, std::string const message) int Gas::run (int argc, char **argv) { + std::cout << "Gas::run" << std::endl; determine_program_dir (argc, argv); + std::cout << "Program dir determined" << std::endl; auto lowercase_string = [](std::string& s) { std::transform ( @@ -69,12 +71,14 @@ int Gas::run (int argc, char **argv) ); }; + std::cout << "Determining arch name" << std::endl; std::string arch_name { generic_gas_name }; const char *first_param = argc > 1 ? argv[1] : nullptr; if (first_param != nullptr && strlen (first_param) > sizeof(Constants::arch_hack_param) && strstr (first_param, Constants::arch_hack_param) == first_param) { arch_name = first_param + (sizeof(Constants::arch_hack_param) - 1); lowercase_string (arch_name); } + std::cout << "arch_name == " << arch_name << std::endl; _program_name = arch_name; std::unique_ptr mc_runner; @@ -112,12 +116,16 @@ int Gas::run (int argc, char **argv) return usage (true /* is_error */, message); } + std::cout << "About to parse arguments" << std::endl; auto&& [terminate, is_error] = parse_arguments (argc, argv, mc_runner); + std::cout << "Arguments parsed; terminate == " << terminate << "; is_error == " << is_error << std::endl; if (terminate || is_error) { return is_error ? Constants::wrapper_general_error_code : 0; } + std::cout << "Getting path to llvm_mc" << std::endl; fs::path llvm_mc = program_dir () / Constants::llvm_mc_name; + std::wcout << "llvm_mc == " << llvm_mc.c_str () << std::endl; bool multiple_input_files = false; bool derive_output_file_name = false; @@ -141,9 +149,11 @@ int Gas::run (int argc, char **argv) } for (fs::path const& input : input_files) { + std::wcout << "running llvm-mc for '" << input.c_str () << std::endl; mc_runner->set_input_file_path (input, derive_output_file_name); int ret = mc_runner->run (llvm_mc); if (ret != 0) { + std::cout << " mc_runner failed with " << ret << std::endl; return ret; } } diff --git a/src/gas/gas.hh b/src/gas/gas.hh index ee5fa39..f3bfd60 100644 --- a/src/gas/gas.hh +++ b/src/gas/gas.hh @@ -217,5 +217,4 @@ namespace xamarin::android::gas }; } -extern xamarin::android::gas::Gas app; #endif // __GAS_HH diff --git a/src/gas/gas.windows.cc b/src/gas/gas.windows.cc index cef3a3f..fcfcf28 100644 --- a/src/gas/gas.windows.cc +++ b/src/gas/gas.windows.cc @@ -2,12 +2,9 @@ #include #include -#include #include #include -#include -#include "constants.hh" #include "exceptions.hh" #include "gas.hh" @@ -17,11 +14,27 @@ void Gas::get_command_line (int &argc, char **&argv) { LPWSTR *argvw = CommandLineToArgvW (GetCommandLineW (), &argc); argv = new char*[argc + 1]; - + memset (argv, 0, argc * sizeof(char*)); for (int i = 0; i < argc; i++) { + std::cout << "Argument " << i << std::endl; int size = WideCharToMultiByte (CP_UTF8, 0, argvw [i], -1, NULL, 0, NULL, NULL); + std::cout << " size: " << size << std::endl; + if (size <= 0) { + // An error, but we ignore it and try to get the other arguments converted. + argv[i] = _strdup (""); + continue; + } + argv [i] = new char [size]; + memset (argv [i], 0, size * sizeof(char)); + std::cout << " copying" << std::endl; WideCharToMultiByte (CP_UTF8, 0, argvw [i], -1, argv [i], size, NULL, NULL); + std::cout << " copied" << std::endl; + } + + std::cout << "Processed arguments: " << std::endl; + for (int i = 0; i < argc; i++) { + std::cout << " [" << i << "] " << argv[i] << std::endl; } argv [argc] = NULL; diff --git a/src/gas/main.cc b/src/gas/main.cc index 9b77d0e..4785f13 100644 --- a/src/gas/main.cc +++ b/src/gas/main.cc @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT +#include #include "gas.hh" -xamarin::android::gas::Gas app; - int main (int argc, char **argv) { + xamarin::android::gas::Gas app; + // On windows this obtains the utf8 version of args app.get_command_line (argc, argv); + std::cout << "Command line converted" << std::endl; // TODO: handle exceptions here (use backward for stacktrace perhaps?) return app.run (argc, argv); } From c5e394297d1baaa3123753f6f171f3feccfe4355 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 21 Mar 2024 19:36:47 +0100 Subject: [PATCH 02/11] Custom command line parser Better option than porting getopt to Windows --- src/gas/CMakeLists.txt | 1 + src/gas/command_line.cc | 77 +++++++++++++++++++++++ src/gas/command_line.hh | 135 ++++++++++++++++++++++++++++++++++++++++ src/gas/constants.hh | 9 +++ src/gas/gas.cc | 56 +++++++++++++++-- src/gas/gas.hh | 15 ++--- 6 files changed, 279 insertions(+), 14 deletions(-) create mode 100644 src/gas/command_line.cc create mode 100644 src/gas/command_line.hh diff --git a/src/gas/CMakeLists.txt b/src/gas/CMakeLists.txt index ced38a4..31aaefc 100644 --- a/src/gas/CMakeLists.txt +++ b/src/gas/CMakeLists.txt @@ -1,4 +1,5 @@ set(GAS_DRIVER_SOURCES + command_line.cc gas.cc llvm_mc_runner.cc llvm_mc_runner_arm32.cc diff --git a/src/gas/command_line.cc b/src/gas/command_line.cc new file mode 100644 index 0000000..905d106 --- /dev/null +++ b/src/gas/command_line.cc @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +#include +#include + +#include "command_line.hh" + +using namespace xamarin::android::gas; +namespace ranges = std::ranges; + +bool CommandLine::parse (std::span options, int argc, TArgType *argv, OptionCallbackFn option_cb) +{ + stdout() << "Got " << options.size() << " options\n" << "Passed args:\n"; + + uint32_t positional_count = 0; + bool next_must_be_positional = false; + + for (int i = 1; i < argc; i++) { + TOptionString option { argv[i] }; + if (option.empty ()) { + continue; + } + + stdout() << " [" << i << "] " << option << "\n"; + + TOptionString::const_iterator iter = option.cbegin (); + + while (iter != option.cend () && *iter == DASH) { + iter++; + } + bool positional = iter == option.cbegin (); + stdout() << std::boolalpha << " Positional? " << positional << "\n"; + + CommandLineStringView option_name; + CommandLineStringView option_value; + if (positional) { + option_cb ({ positional_count++ }, { option }); + continue; + } + + TOptionString::const_iterator name_start = iter; + + while (iter != option.cend () && *iter != EQUALS) { + iter++; + } + + option_name = { name_start, iter }; + + bool has_value = iter != option.cend (); + stdout() << " Has value? " << has_value << "\n"; + + if (has_value) { + iter++; + option_value = { iter, option.cend () }; + } + + stdout() << " Option name: " << TOptionString (option_name) << "\n"; + stdout() << " Option value: " << TOptionString (option_value) << "\n"; + + auto matching_option = [this, &option_name] (CommandLineOption const& o) -> bool { + if (o.name != option_name) { + return false; + } + + return o.arch == TargetArchitecture::Any || o.arch == target_arch; + }; + + auto match = ranges::find_if (options, matching_option); + if (match != options.end ()) { + stdout() << " found matching option\n"; + } else { + stderr() << "Uncrecognized option '" << option << "'\n"; + } + } + + return true; +} diff --git a/src/gas/command_line.hh b/src/gas/command_line.hh new file mode 100644 index 0000000..0b79974 --- /dev/null +++ b/src/gas/command_line.hh @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +#if !defined (GAS_COMMAND_LINE_HH) +#define GAS_COMMAND_LINE_HH + +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#endif + +#include "constants.hh" + +namespace xamarin::android::gas +{ +#if !defined (_WIN32) + using CommandLineString = std::string; + using CommandLineStringView = std::string_view; +#else + using CommandLineString = std::wstring; + using CommandLineStringView = std::wstring_view; +#endif + + enum class Argument + { + Required, + NotRequired, + }; + + struct CommandLineOption + { + CommandLineStringView name; + uint32_t id; + Argument argument; + TargetArchitecture arch; + + constexpr CommandLineOption (CommandLineStringView const& _name, uint32_t _id, Argument _argument, TargetArchitecture _arch) + : name (_name), + id (_id), + argument (_argument), + arch (_arch) + {} + + constexpr CommandLineOption (CommandLineStringView const& _name, uint32_t _id, TargetArchitecture _arch) + : CommandLineOption (_name, _id, Argument::NotRequired, _arch) + {} + + constexpr CommandLineOption (CommandLineStringView const& _name, uint32_t _id, Argument _argument) + : CommandLineOption (_name, _id, _argument, TargetArchitecture::Any) + {} + + constexpr CommandLineOption (CommandLineStringView const& _name, uint32_t _id) + : CommandLineOption (_name, _id, Argument::NotRequired, TargetArchitecture::Any) + {} + }; + + class CommandLine + { +#if !defined(_WIN32) + static constexpr bool is_windows = false; +#else + static constexpr bool is_windows = true; +#endif + + public: +#if !defined(_WIN32) + using TArgType = char*; + using TOptionString = std::string; + + private: + static inline constexpr char DASH = '-'; + static inline constexpr char EQUALS = '='; +#else + using TArgType = LPWSTR; + using TOptionString = std::wstring; + + private: + static inline constexpr wchar_t DASH = L'-'; + static inline constexpr wchar_t EQUALS = L'='; +#endif + + public: + using TOptionValue = std::variant; + using TCallbackOption = std::variant; + using OptionCallbackFn = std::function; + + public: + explicit CommandLine (TargetArchitecture _target_arch) noexcept + : target_arch (_target_arch) + {} + + template + bool parse (std::array const& options, int argc, TArgType *argv, OptionCallbackFn option_cb) + { + return parse (std::span (options.data(), options.size()), argc, argv, option_cb); + } + + private: + bool parse (std::span options, int argc, TArgType *argv, OptionCallbackFn option_cb); + + static constexpr auto& stdout () noexcept + { + if constexpr (is_windows) { + return std::wcout; + } else { + return std::cout; + } + } + + static constexpr auto& stderr () noexcept + { + if constexpr (is_windows) { + return std::wcerr; + } else { + return std::cerr; + } + } + + private: + TargetArchitecture target_arch; + }; +} + +#if !defined (_WIN32) +#define CLISTR(_str_lit_) std::string_view { _str_lit_ } +#else +#define CLISTR(_str_lit_) std::wstring_view { L##_str_lit_ } +#endif + +#endif // ndef GAS_COMMAND_LINE_HH diff --git a/src/gas/constants.hh b/src/gas/constants.hh index 6c28835..253bc57 100644 --- a/src/gas/constants.hh +++ b/src/gas/constants.hh @@ -23,5 +23,14 @@ namespace xamarin::android::gas static constexpr int wrapper_exec_failed_error_code = wrapper_general_error_code + 4; static constexpr int wrapper_wait_failed_error_code = wrapper_general_error_code + 5; }; + + enum class TargetArchitecture + { + Any, + ARM32, + ARM64, + X86, + X64, + }; } #endif diff --git a/src/gas/gas.cc b/src/gas/gas.cc index 6c0bc6d..c3b36a5 100644 --- a/src/gas/gas.cc +++ b/src/gas/gas.cc @@ -3,10 +3,12 @@ #include #endif +#include #include #include #include +#include "command_line.hh" #include "constants.hh" #include "gas.hh" #include "llvm_mc_runner.hh" @@ -183,6 +185,41 @@ int Gas::run (int argc, char **argv) return 0; } +constexpr std::array all_options {{ + // Arguments ignored by GAS, we shall ignore them silently too + { CLISTR("divide"), OPTION_IGNORE }, + { CLISTR("k"), OPTION_IGNORE }, + { CLISTR("nocpp"), OPTION_IGNORE }, + { CLISTR("Qn"), OPTION_IGNORE }, + { CLISTR("Qy"), OPTION_IGNORE }, + { CLISTR("s"), OPTION_IGNORE }, + { CLISTR("w"), OPTION_IGNORE }, + { CLISTR("X"), OPTION_IGNORE }, + + // Global GAS arguments we support + { CLISTR("o"), OPTION_O, Argument::Required }, + { CLISTR("warn"), OPTION_WARN }, + { CLISTR("g"), OPTION_G }, + { CLISTR("gen-debug"), OPTION_G }, + + // Arguments handled by us, not passed to llvm-mc + { CLISTR("h"), OPTION_HELP }, + { CLISTR("help"), OPTION_HELP }, + { CLISTR("V"), OPTION_VERSION }, + { CLISTR("version"), OPTION_VERSION_EXIT }, + + // x86 arguments + { CLISTR("32"), OPTION_IGNORE, TargetArchitecture::X86 }, // llvm-mc doesn't need this + { CLISTR("64"), OPTION_IGNORE, TargetArchitecture::X86 }, // llvm-mc doesn't need this + + // x64 arguments + { CLISTR("32"), OPTION_IGNORE, TargetArchitecture::X64 }, // llvm-mc doesn't need this + { CLISTR("64"), OPTION_IGNORE, TargetArchitecture::X64 }, // llvm-mc doesn't need this + + // Arm32 arguments + { CLISTR("mfpu"), OPTION_MFPU, Argument::Required, TargetArchitecture::ARM32 }, +}}; + std::vector