From b3cc1e1c42d8b367f2d0b1a93c236abe1cc94b34 Mon Sep 17 00:00:00 2001 From: ruki Date: Fri, 16 Jun 2017 15:45:31 +0800 Subject: replace old find compiler scripts and fix string.endswith --- core/src/demo/xmake.lua | 2 +- core/src/xmake/machine.c | 4 +- core/src/xmake/makefile | 1 - core/src/xmake/string/endswith.c | 6 +- core/src/xmake/string/startswith.c | 2 +- core/src/xmake/string/strcmp.c | 57 -- xmake/core/_xmake_main.lua | 5 +- xmake/core/base/interpreter.lua | 2 +- xmake/core/base/string.lua | 7 - xmake/core/project/template.lua | 8 +- xmake/core/sandbox/modules/import.lua | 6 +- xmake/core/sandbox/modules/os.lua | 7 - xmake/core/sandbox/sandbox.lua | 2 +- xmake/modules/detect/tool/find_7z.lua | 5 +- xmake/modules/detect/tool/find_ar.lua | 2 +- xmake/modules/detect/tool/find_brew.lua | 5 +- xmake/modules/detect/tool/find_ccache.lua | 2 +- xmake/modules/detect/tool/find_cl.lua | 2 +- xmake/modules/detect/tool/find_clang.lua | 2 +- xmake/modules/detect/tool/find_clangxx.lua | 2 +- xmake/modules/detect/tool/find_curl.lua | 5 +- xmake/modules/detect/tool/find_dmd.lua | 2 +- xmake/modules/detect/tool/find_doxygen.lua | 5 +- xmake/modules/detect/tool/find_gcc.lua | 2 +- xmake/modules/detect/tool/find_gccgo.lua | 2 +- xmake/modules/detect/tool/find_gdb.lua | 2 +- xmake/modules/detect/tool/find_gdc.lua | 2 +- xmake/modules/detect/tool/find_git.lua | 5 +- xmake/modules/detect/tool/find_go.lua | 2 +- xmake/modules/detect/tool/find_gxx.lua | 2 +- xmake/modules/detect/tool/find_gzip.lua | 5 +- xmake/modules/detect/tool/find_ldc2.lua | 2 +- xmake/modules/detect/tool/find_lib.lua | 2 +- xmake/modules/detect/tool/find_link.lua | 2 +- xmake/modules/detect/tool/find_lipo.lua | 2 +- xmake/modules/detect/tool/find_lldb.lua | 2 +- xmake/modules/detect/tool/find_ml.lua | 2 +- xmake/modules/detect/tool/find_ml64.lua | 59 ++ xmake/modules/detect/tool/find_rc.lua | 58 ++ xmake/modules/detect/tool/find_rustc.lua | 2 +- xmake/modules/detect/tool/find_sudo.lua | 5 +- xmake/modules/detect/tool/find_swiftc.lua | 2 +- xmake/modules/detect/tool/find_tar.lua | 5 +- xmake/modules/detect/tool/find_unzip.lua | 5 +- xmake/modules/detect/tool/find_wget.lua | 5 +- xmake/modules/detect/tool/find_zip.lua | 5 +- xmake/modules/lib/detect/find_tool.lua | 8 + xmake/platforms/checker.lua | 56 +- xmake/platforms/iphoneos/check.lua | 16 +- xmake/platforms/watchos/check.lua | 16 +- xmake/platforms/windows/check.lua | 8 +- xmake/scripts/gas-preprocessor.pl | 1025 ++++++++++++++++++++++++++++ xmake/tools/utils/gas-preprocessor.pl | 1025 ---------------------------- 53 files changed, 1245 insertions(+), 1230 deletions(-) delete mode 100644 core/src/xmake/string/strcmp.c create mode 100644 xmake/modules/detect/tool/find_ml64.lua create mode 100644 xmake/modules/detect/tool/find_rc.lua create mode 100755 xmake/scripts/gas-preprocessor.pl delete mode 100755 xmake/tools/utils/gas-preprocessor.pl diff --git a/core/src/demo/xmake.lua b/core/src/demo/xmake.lua index 9f4fd2f0d..40d089f7f 100644 --- a/core/src/demo/xmake.lua +++ b/core/src/demo/xmake.lua @@ -36,6 +36,6 @@ target("demo") -- add the resource files (it will be enabled after publishing new version) if is_plat("windows") then --- add_files("*.rc") + add_files("*.rc") end diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c index e1638e1ab..7f1acfbd0 100644 --- a/core/src/xmake/machine.c +++ b/core/src/xmake/machine.c @@ -99,7 +99,6 @@ tb_int_t xm_winreg_query(lua_State* lua); #endif // the string functions -tb_int_t xm_string_strcmp(lua_State* lua); tb_int_t xm_string_endswith(lua_State* lua); tb_int_t xm_string_startswith(lua_State* lua); @@ -172,8 +171,7 @@ static luaL_Reg const g_path_functions[] = // the string functions static luaL_Reg const g_string_functions[] = { - { "strcmp", xm_string_strcmp } -, { "endswith", xm_string_endswith } + { "endswith", xm_string_endswith } , { "startswith", xm_string_startswith } , { tb_null, tb_null } }; diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile index efc32d94d..e9f5badce 100644 --- a/core/src/xmake/makefile +++ b/core/src/xmake/makefile @@ -45,7 +45,6 @@ xmake_C_FILES += \ path/translate \ path/is_absolute \ winreg/query \ - string/strcmp \ string/endswith \ string/startswith \ process/open \ diff --git a/core/src/xmake/string/endswith.c b/core/src/xmake/string/endswith.c index 241e59254..8de61e2bb 100644 --- a/core/src/xmake/string/endswith.c +++ b/core/src/xmake/string/endswith.c @@ -49,9 +49,9 @@ tb_int_t xm_string_endswith(lua_State* lua) tb_char_t const* suffix = luaL_checklstring(lua, 2, &suffix_size); tb_check_return_val(string && suffix, 0); - // done string:endswith(suffix) - if (string_size >= suffix_size) - lua_pushboolean(lua, !tb_strcmp(string + string_size - suffix_size, suffix)); + // string:endswith(suffix)? + lua_pushboolean(lua, string_size >= suffix_size && !tb_strcmp(string + string_size - suffix_size, suffix)); + // ok return 1; diff --git a/core/src/xmake/string/startswith.c b/core/src/xmake/string/startswith.c index 84766e5ca..de039dede 100644 --- a/core/src/xmake/string/startswith.c +++ b/core/src/xmake/string/startswith.c @@ -48,7 +48,7 @@ tb_int_t xm_string_startswith(lua_State* lua) tb_char_t const* prefix = luaL_checklstring(lua, 2, &prefix_size); tb_check_return_val(string && prefix, 0); - // done string:startswith(prefix) + // string:startswith(prefix)? lua_pushboolean(lua, !tb_strncmp(string, prefix, (tb_size_t)prefix_size)); // ok diff --git a/core/src/xmake/string/strcmp.c b/core/src/xmake/string/strcmp.c deleted file mode 100644 index 2ad06f27d..000000000 --- a/core/src/xmake/string/strcmp.c +++ /dev/null @@ -1,57 +0,0 @@ -/*!The Make-like Build Utility based on Lua - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (C) 2015 - 2017, TBOOX Open Source Group. - * - * @author ruki - * @file strcmp.c - * - */ - -/* ////////////////////////////////////////////////////////////////////////////////////// - * trace - */ -#define TB_TRACE_MODULE_NAME "strcmp" -#define TB_TRACE_MODULE_DEBUG (0) - -/* ////////////////////////////////////////////////////////////////////////////////////// - * includes - */ -#include "prefix.h" - -/* ////////////////////////////////////////////////////////////////////////////////////// - * implementation - */ - -// string:strcmp(s1, s2) -tb_int_t xm_string_strcmp(lua_State* lua) -{ - // check - tb_assert_and_check_return_val(lua, 0); - - // get the strings - tb_char_t const* s1 = luaL_checkstring(lua, 1); - tb_char_t const* s2 = luaL_checkstring(lua, 2); - tb_check_return_val(s1 && s2, 0); - - // compare them - lua_pushinteger(lua, tb_strcmp(s1, s2)); - - // ok - return 1; -} diff --git a/xmake/core/_xmake_main.lua b/xmake/core/_xmake_main.lua index 39bb5f225..58af78d66 100644 --- a/xmake/core/_xmake_main.lua +++ b/xmake/core/_xmake_main.lua @@ -33,13 +33,10 @@ xmake._VERSION_SHORT = _VERSION_SHORT xmake._PROGRAM_DIR = _PROGRAM_DIR xmake._PROGRAM_FILE = _PROGRAM_FILE xmake._PROJECT_DIR = _PROJECT_DIR -xmake._CORE_DIR = _PROGRAM_DIR .. "/core" -xmake._TOOLS_DIR = _PROGRAM_DIR .. "/tools" -xmake._TEMPLATES_DIR = _PROGRAM_DIR .. "/templates" xmake._PROJECT_FILE = "xmake.lua" -- init package path -package.path = xmake._CORE_DIR .. "/?.lua;" .. package.path +package.path = xmake._PROGRAM_DIR .. "/core/?.lua;" .. package.path -- load modules local main = require("main") diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua index 5c51b35e4..c23fa8457 100644 --- a/xmake/core/base/interpreter.lua +++ b/xmake/core/base/interpreter.lua @@ -700,7 +700,7 @@ function interpreter.new() instance:api_register(nil, "set_xmakever", interpreter.api_builtin_set_xmakever) -- load builtin module files - local builtin_module_files = os.match(path.join(xmake._CORE_DIR, "sandbox/modules/interpreter/*.lua")) + local builtin_module_files = os.match(path.join(os.programdir(), "core/sandbox/modules/interpreter/*.lua")) if builtin_module_files then for _, builtin_module_file in ipairs(builtin_module_files) do diff --git a/xmake/core/base/string.lua b/xmake/core/base/string.lua index f54f7b1a3..97945851e 100644 --- a/xmake/core/base/string.lua +++ b/xmake/core/base/string.lua @@ -131,13 +131,6 @@ function string.join(items, sep) return str end --- less than -function string:less(other) - - -- < ? - return string.strcmp(self, other) < 0 -end - -- try to format function string.tryformat(format, ...) diff --git a/xmake/core/project/template.lua b/xmake/core/project/template.lua index a306bf622..cbc1551a8 100644 --- a/xmake/core/project/template.lua +++ b/xmake/core/project/template.lua @@ -90,7 +90,7 @@ function template._replace(macros, macrofiles) -- make all files local files = {} for _, macrofile in ipairs(table.wrap(macrofiles)) do - local matchfiles = os.match(macrofile) + local matchfiles = os.files(macrofile) if matchfiles then table.join2(files, matchfiles) end @@ -114,7 +114,7 @@ function template.languages() local list = {} -- get the language list - local languages = os.match(xmake._TEMPLATES_DIR .. "/*", true) + local languages = os.dirs(path.join(os.programdir(), "templates", "*")) if languages then for _, v in ipairs(languages) do table.insert(list, path.basename(v)) @@ -137,7 +137,7 @@ function template.templates(language) -- load all templates local templates = {} - local templatefiles = os.match(string.format("%s/%s/**/template.lua", xmake._TEMPLATES_DIR, language)) + local templatefiles = os.files(path.join(os.programdir(), "templates", language, "**", "template.lua")) if templatefiles then -- load template @@ -159,7 +159,7 @@ function template.templates(language) end -- sort templates - table.sort(templates, function(a, b) return a.description:less(b.description) end) + table.sort(templates, function(a, b) return a.description < b.description end) -- ok? return templates diff --git a/xmake/core/sandbox/modules/import.lua b/xmake/core/sandbox/modules/import.lua index 885378750..a18a5231b 100644 --- a/xmake/core/sandbox/modules/import.lua +++ b/xmake/core/sandbox/modules/import.lua @@ -300,7 +300,7 @@ function sandbox_import.import(name, args) assert(rootdir) -- the sandbox modules directory - local modules_sandbox_dir = path.join(xmake._CORE_DIR, "sandbox/modules/import") + local modules_sandbox_dir = path.join(os.programdir(), "core/sandbox/modules/import") -- the extension modules directory local modules_extension_dir = path.join(os.programdir(), "modules") @@ -313,8 +313,8 @@ function sandbox_import.import(name, args) { rootdir -- load module from the given root directory first , path.join(global.directory(), "modules") -- load module from the user global modules directory - , path.join(xmake._PROGRAM_DIR, "modules") -- load module from the extension modules directory - , path.join(xmake._CORE_DIR, "sandbox/modules/import") -- load module from the sandbox core modules directory + , path.join(os.programdir(), "modules") -- load module from the extension modules directory + , path.join(os.programdir(), "core/sandbox/modules/import") -- load module from the sandbox core modules directory } -- load module diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index 657364cb2..089f42d7e 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -224,13 +224,6 @@ function sandbox_os.tmpfile() return tmpfile end --- get the tools directory -function sandbox_os.toolsdir() - - -- get it - return xmake._TOOLS_DIR -end - -- get the script directory function sandbox_os.scriptdir() diff --git a/xmake/core/sandbox/sandbox.lua b/xmake/core/sandbox/sandbox.lua index 77b7003e2..222312b1c 100644 --- a/xmake/core/sandbox/sandbox.lua +++ b/xmake/core/sandbox/sandbox.lua @@ -107,7 +107,7 @@ function sandbox._new() table.inherit2(instance, sandbox) -- load builtin module files - local builtin_module_files = os.match(path.join(xmake._CORE_DIR, "sandbox/modules/*.lua")) + local builtin_module_files = os.match(path.join(os.programdir(), "core/sandbox/modules/*.lua")) if builtin_module_files then for _, builtin_module_file in ipairs(builtin_module_files) do diff --git a/xmake/modules/detect/tool/find_7z.lua b/xmake/modules/detect/tool/find_7z.lua index 58a4ea24e..bc5c3d340 100644 --- a/xmake/modules/detect/tool/find_7z.lua +++ b/xmake/modules/detect/tool/find_7z.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("7z", {}, "--help") + local program = find_program(opt.program or "7z", opt.pathes, opt.check or "--help") -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_ar.lua b/xmake/modules/detect/tool/find_ar.lua index 2cb78ddff..6bbf840c5 100644 --- a/xmake/modules/detect/tool/find_ar.lua +++ b/xmake/modules/detect/tool/find_ar.lua @@ -66,5 +66,5 @@ function main(opt) opt = opt or {} -- find program - return find_program(opt.program or "ar", {}, _check) + return find_program(opt.program or "ar", opt.pathes, opt.check or _check) end diff --git a/xmake/modules/detect/tool/find_brew.lua b/xmake/modules/detect/tool/find_brew.lua index 07fb8dae6..e4c07403f 100644 --- a/xmake/modules/detect/tool/find_brew.lua +++ b/xmake/modules/detect/tool/find_brew.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("brew") + local program = find_program(opt.program or "brew", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_ccache.lua b/xmake/modules/detect/tool/find_ccache.lua index c32bbc4b6..9e4fe4aa6 100644 --- a/xmake/modules/detect/tool/find_ccache.lua +++ b/xmake/modules/detect/tool/find_ccache.lua @@ -45,7 +45,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "ccache") + local program = find_program(opt.program or "ccache", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_cl.lua b/xmake/modules/detect/tool/find_cl.lua index 8287120f9..3ab7cf5c1 100644 --- a/xmake/modules/detect/tool/find_cl.lua +++ b/xmake/modules/detect/tool/find_cl.lua @@ -44,7 +44,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "cl.exe", {}, function (program) os.run(program) end) + local program = find_program(opt.program or "cl.exe", opt.pathes, opt.check or function (program) os.run(program) end) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_clang.lua b/xmake/modules/detect/tool/find_clang.lua index 1de30f6a9..5e1dc95d4 100644 --- a/xmake/modules/detect/tool/find_clang.lua +++ b/xmake/modules/detect/tool/find_clang.lua @@ -45,7 +45,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "clang") + local program = find_program(opt.program or "clang", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_clangxx.lua b/xmake/modules/detect/tool/find_clangxx.lua index c7d9f45d1..77e80304f 100644 --- a/xmake/modules/detect/tool/find_clangxx.lua +++ b/xmake/modules/detect/tool/find_clangxx.lua @@ -45,7 +45,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "clang++") + local program = find_program(opt.program or "clang++", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_curl.lua b/xmake/modules/detect/tool/find_curl.lua index 3b49247ef..a5ba49e20 100644 --- a/xmake/modules/detect/tool/find_curl.lua +++ b/xmake/modules/detect/tool/find_curl.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("curl") + local program = find_program(opt.program or "curl", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_dmd.lua b/xmake/modules/detect/tool/find_dmd.lua index fe47fc618..f244c0ad0 100644 --- a/xmake/modules/detect/tool/find_dmd.lua +++ b/xmake/modules/detect/tool/find_dmd.lua @@ -44,7 +44,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "dmd") + local program = find_program(opt.program or "dmd", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_doxygen.lua b/xmake/modules/detect/tool/find_doxygen.lua index 3b3a6bee4..5824c574c 100644 --- a/xmake/modules/detect/tool/find_doxygen.lua +++ b/xmake/modules/detect/tool/find_doxygen.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("doxygen", { "/usr/bin", "/usr/local/bin"}) + local program = find_program(opt.program or "doxygen", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_gcc.lua b/xmake/modules/detect/tool/find_gcc.lua index 0076d328f..d7cbce7d2 100644 --- a/xmake/modules/detect/tool/find_gcc.lua +++ b/xmake/modules/detect/tool/find_gcc.lua @@ -45,7 +45,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "gcc") + local program = find_program(opt.program or "gcc", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_gccgo.lua b/xmake/modules/detect/tool/find_gccgo.lua index eaff5e3ea..a12be3067 100644 --- a/xmake/modules/detect/tool/find_gccgo.lua +++ b/xmake/modules/detect/tool/find_gccgo.lua @@ -44,7 +44,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "gccgo") + local program = find_program(opt.program or "gccgo", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_gdb.lua b/xmake/modules/detect/tool/find_gdb.lua index ff206288c..3e698022a 100644 --- a/xmake/modules/detect/tool/find_gdb.lua +++ b/xmake/modules/detect/tool/find_gdb.lua @@ -46,7 +46,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "gdb") + local program = find_program(opt.program or "gdb", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_gdc.lua b/xmake/modules/detect/tool/find_gdc.lua index a094cf7ee..a2b2b4c9a 100644 --- a/xmake/modules/detect/tool/find_gdc.lua +++ b/xmake/modules/detect/tool/find_gdc.lua @@ -44,7 +44,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "gdc") + local program = find_program(opt.program or "gdc", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_git.lua b/xmake/modules/detect/tool/find_git.lua index 12f08978d..b21455b0c 100644 --- a/xmake/modules/detect/tool/find_git.lua +++ b/xmake/modules/detect/tool/find_git.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("git") + local program = find_program(opt.program or "git", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_go.lua b/xmake/modules/detect/tool/find_go.lua index 9932f73ba..0b1b9103e 100644 --- a/xmake/modules/detect/tool/find_go.lua +++ b/xmake/modules/detect/tool/find_go.lua @@ -44,7 +44,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "go", {}, "version") + local program = find_program(opt.program or "go", opt.pathes, opt.check or "version") -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_gxx.lua b/xmake/modules/detect/tool/find_gxx.lua index a58cfe75f..5ab35fa44 100644 --- a/xmake/modules/detect/tool/find_gxx.lua +++ b/xmake/modules/detect/tool/find_gxx.lua @@ -45,7 +45,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "g++") + local program = find_program(opt.program or "g++", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_gzip.lua b/xmake/modules/detect/tool/find_gzip.lua index d1b286bba..95d364971 100644 --- a/xmake/modules/detect/tool/find_gzip.lua +++ b/xmake/modules/detect/tool/find_gzip.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("gzip") + local program = find_program(opt.program or "gzip", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_ldc2.lua b/xmake/modules/detect/tool/find_ldc2.lua index 77df85852..8b2f42c5d 100644 --- a/xmake/modules/detect/tool/find_ldc2.lua +++ b/xmake/modules/detect/tool/find_ldc2.lua @@ -44,7 +44,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "ldc2") + local program = find_program(opt.program or "ldc2", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_lib.lua b/xmake/modules/detect/tool/find_lib.lua index 5b6545f40..107c33cbb 100644 --- a/xmake/modules/detect/tool/find_lib.lua +++ b/xmake/modules/detect/tool/find_lib.lua @@ -45,7 +45,7 @@ function main(opt) -- find program local verinfo = nil - local program = find_program(opt.program or "lib.exe", {}, function (program) + local program = find_program(opt.program or "lib.exe", opt.pathes, opt.check or function (program) -- make an stub source file local libraryfile = os.tmpfile() .. ".lib" diff --git a/xmake/modules/detect/tool/find_link.lua b/xmake/modules/detect/tool/find_link.lua index 209fa1300..d30fe6fbe 100644 --- a/xmake/modules/detect/tool/find_link.lua +++ b/xmake/modules/detect/tool/find_link.lua @@ -45,7 +45,7 @@ function main(opt) -- find program local verinfo = nil - local program = find_program(opt.program or "link.exe", {}, function (program) + local program = find_program(opt.program or "link.exe", opt.pathes, opt.check or function (program) -- make an stub source file local binaryfile = os.tmpfile() .. ".exe" diff --git a/xmake/modules/detect/tool/find_lipo.lua b/xmake/modules/detect/tool/find_lipo.lua index 85d1fba76..27be94c1f 100644 --- a/xmake/modules/detect/tool/find_lipo.lua +++ b/xmake/modules/detect/tool/find_lipo.lua @@ -44,5 +44,5 @@ function main(opt) opt = opt or {} -- find program - return find_program(opt.program or "lipo", {}, function (program) os.run("%s -info %s", program, os.programfile()) end) + return find_program(opt.program or "lipo", opt.pathes, opt.check or function (program) os.run("%s -info %s", program, os.programfile()) end) end diff --git a/xmake/modules/detect/tool/find_lldb.lua b/xmake/modules/detect/tool/find_lldb.lua index 3c15c2fb1..8a6e86341 100644 --- a/xmake/modules/detect/tool/find_lldb.lua +++ b/xmake/modules/detect/tool/find_lldb.lua @@ -46,7 +46,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "lldb") + local program = find_program(opt.program or "lldb", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_ml.lua b/xmake/modules/detect/tool/find_ml.lua index b4407e452..da3f026ac 100644 --- a/xmake/modules/detect/tool/find_ml.lua +++ b/xmake/modules/detect/tool/find_ml.lua @@ -44,7 +44,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "ml.exe", {}, function (program) os.run(program) end) + local program = find_program(opt.program or "ml.exe", opt.pathes, opt.check or function (program) os.run(program) end) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_ml64.lua b/xmake/modules/detect/tool/find_ml64.lua new file mode 100644 index 000000000..d2377c19e --- /dev/null +++ b/xmake/modules/detect/tool/find_ml64.lua @@ -0,0 +1,59 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file find_ml64.lua +-- + +-- imports +import("lib.detect.find_program") +import("lib.detect.find_programver") + +-- find ml64 +-- +-- @param opt the argument options, .e.g {version = true} +-- +-- @return program, version +-- +-- @code +-- +-- local ml64 = find_ml64() +-- +-- @endcode +-- +function main(opt) + + -- init options + opt = opt or {} + + -- find program + local program = find_program(opt.program or "ml64.exe", opt.pathes, opt.check or function (program) os.run(program) end) + + -- find program version + local version = nil + if program and opt and opt.version then + version = find_programver(program, function () local _, info = os.iorun(program); return info end, + function (output) return output:match("Version (%d+%.?%d*%.?%d*.-)%s") end) + end + + -- ok? + return program, version +end + diff --git a/xmake/modules/detect/tool/find_rc.lua b/xmake/modules/detect/tool/find_rc.lua new file mode 100644 index 000000000..cbd24e82a --- /dev/null +++ b/xmake/modules/detect/tool/find_rc.lua @@ -0,0 +1,58 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file find_rc.lua +-- + +-- imports +import("lib.detect.find_program") +import("lib.detect.find_programver") + +-- find rc +-- +-- @param opt the argument options, .e.g {version = true} +-- +-- @return program, version +-- +-- @code +-- +-- local rc = find_rc() +-- +-- @endcode +-- +function main(opt) + + -- init options + opt = opt or {} + + -- find program + local program = find_program(opt.program or "rc.exe", opt.pathes, "-?") + + -- find program version + local version = nil + if program and opt and opt.version then + version = find_programver(program, "-?", function (output) return output:match("Version (%d+%.?%d*%.?%d*.-)%s") end) + end + + -- ok? + return program, version +end + diff --git a/xmake/modules/detect/tool/find_rustc.lua b/xmake/modules/detect/tool/find_rustc.lua index 938c6c180..d01380d72 100644 --- a/xmake/modules/detect/tool/find_rustc.lua +++ b/xmake/modules/detect/tool/find_rustc.lua @@ -44,7 +44,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "rustc") + local program = find_program(opt.program or "rustc", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_sudo.lua b/xmake/modules/detect/tool/find_sudo.lua index 3d0082b17..3306f2fd3 100644 --- a/xmake/modules/detect/tool/find_sudo.lua +++ b/xmake/modules/detect/tool/find_sudo.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("sudo", {}, "-h") + local program = find_program(opt.program or "sudo", opt.pathes, opt.check or "-h") -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_swiftc.lua b/xmake/modules/detect/tool/find_swiftc.lua index cc9bdf4d6..cf9373739 100644 --- a/xmake/modules/detect/tool/find_swiftc.lua +++ b/xmake/modules/detect/tool/find_swiftc.lua @@ -45,7 +45,7 @@ function main(opt) opt = opt or {} -- find program - local program = find_program(opt.program or "swiftc") + local program = find_program(opt.program or "swiftc", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_tar.lua b/xmake/modules/detect/tool/find_tar.lua index e091d3204..f37843171 100644 --- a/xmake/modules/detect/tool/find_tar.lua +++ b/xmake/modules/detect/tool/find_tar.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("tar") + local program = find_program(opt.program or "tar", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_unzip.lua b/xmake/modules/detect/tool/find_unzip.lua index 19c30f517..c3533cd54 100644 --- a/xmake/modules/detect/tool/find_unzip.lua +++ b/xmake/modules/detect/tool/find_unzip.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("unzip", {}, "-v") + local program = find_program(opt.program or "unzip", opt.pathes, opt.check or "-v") -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_wget.lua b/xmake/modules/detect/tool/find_wget.lua index 59a9c7d63..5f8dd7594 100644 --- a/xmake/modules/detect/tool/find_wget.lua +++ b/xmake/modules/detect/tool/find_wget.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("wget") + local program = find_program(opt.program or "wget", opt.pathes, opt.check) -- find program version local version = nil diff --git a/xmake/modules/detect/tool/find_zip.lua b/xmake/modules/detect/tool/find_zip.lua index b424d6e99..71405d3ff 100644 --- a/xmake/modules/detect/tool/find_zip.lua +++ b/xmake/modules/detect/tool/find_zip.lua @@ -40,9 +40,12 @@ import("lib.detect.find_programver") -- @endcode -- function main(opt) + + -- init options + opt = opt or {} -- find program - local program = find_program("zip", {}, "-v") + local program = find_program(opt.program or "zip", opt.pathes, opt.check or "-v") -- find program version local version = nil diff --git a/xmake/modules/lib/detect/find_tool.lua b/xmake/modules/lib/detect/find_tool.lua index 74d446bb4..0911bea20 100644 --- a/xmake/modules/lib/detect/find_tool.lua +++ b/xmake/modules/lib/detect/find_tool.lua @@ -29,9 +29,17 @@ import("lib.detect.find_programver") -- find tool from modules function _find_from_modules(name, opt) + -- strip arguments with spaces + name = name:split("%s+")[1] + -- replace "+" to "x" name = name:gsub("%+", "x") + -- strip suffix on windows + if os.host() == "windows" and name:endswith(".exe") then + name = name:sub(1, #name - 4) + end + -- "detect.tool.find_xxx" exists? if os.isfile(path.join(os.programdir(), "modules", "detect", "tool", "find_" .. name .. ".lua")) then local find_tool = import("detect.tool.find_" .. name) diff --git a/xmake/platforms/checker.lua b/xmake/platforms/checker.lua index 870b51053..c6cb2b581 100644 --- a/xmake/platforms/checker.lua +++ b/xmake/platforms/checker.lua @@ -23,10 +23,10 @@ -- -- imports -import("core.tool.tool") import("core.base.option") import("detect.sdk.find_xcode_dir") import("detect.sdk.find_xcode_sdkvers") +import("lib.detect.find_tool") -- find the given tool function _toolchain_check(config, toolkind, toolinfo) @@ -39,61 +39,23 @@ function _toolchain_check(config, toolkind, toolinfo) local name = toolinfo.name -- get cross - local cross = config.get("cross") or toolinfo.cross + local cross = config.get("cross") or toolinfo.cross or "" - -- get shell name from the env if not cross-compilation - if cross and cross:trim() == "" then - local shellname = os.getenv(toolkind:upper():split('-')[1]) - if shellname and shellname:trim() ~= "" then - toolpath = tool.check(shellname) + -- get program name from the env if not cross-compilation + if cross:trim() == "" then + local program = os.getenv(toolkind:upper():split('-')[1]) + if program and program:trim() ~= "" then + toolpath = find_tool(name, {program = program}) end end - -- check it using the custom script - if not toolpath and toolinfo.check then - - -- check it - try - { - function () - - -- check it - toolinfo.check(cross .. name) - - -- ok - toolpath = cross .. name - end - } - end - - -- get toolchains - local toolchains = config.get("toolchains") - if not toolchains then - local sdkdir = config.get("sdk") - if sdkdir then - toolchains = path.join(sdkdir, "bin") - end - end - - -- attempt to check it from the given cross toolchains - if not toolpath and toolchains then - toolpath = tool.check(cross .. name, toolchains) - end - - -- attempt to check it with cross prefix + -- attempt to check it if not toolpath then - toolpath = tool.check(cross .. name) - end - - -- attempt to check it without cross prefix - if not toolpath then - toolpath = tool.check(name) + toolpath = find_tool(name, {program = cross .. name, pathes = config.get("toolchains"), check = toolinfo.check}) end -- check ok? if toolpath then - - -- update config config.set(toolkind, toolpath) end diff --git a/xmake/platforms/iphoneos/check.lua b/xmake/platforms/iphoneos/check.lua index b3fa9b728..a12a53801 100644 --- a/xmake/platforms/iphoneos/check.lua +++ b/xmake/platforms/iphoneos/check.lua @@ -25,20 +25,6 @@ -- imports import(".checker") --- check the as -function _check_as(shellname) - - -- make an empty tmp.S - local tmpfile = os.tmpfile() .. ".S" - io.writefile(tmpfile, "") - - -- check it - os.run("%s -arch armv7 -o %s -c %s", shellname, os.nuldev(), tmpfile) - - -- remove this tmp.S - os.rm(tmpfile) -end - -- get toolchains function _toolchains(config) @@ -82,7 +68,7 @@ function _toolchains(config) if simulator then checker.toolchain_insert(toolchains, "as", cross, "clang", "the assember") else - checker.toolchain_insert(toolchains, "as", path.join(os.toolsdir(), "utils/gas-preprocessor.pl " .. cross), "clang", "the assember", _check_as) + checker.toolchain_insert(toolchains, "as", path.join(os.programdir(), "scripts", "gas-preprocessor.pl " .. cross), "clang", "the assember") end -- save toolchains diff --git a/xmake/platforms/watchos/check.lua b/xmake/platforms/watchos/check.lua index c6ce73e21..60a923fa8 100644 --- a/xmake/platforms/watchos/check.lua +++ b/xmake/platforms/watchos/check.lua @@ -25,20 +25,6 @@ -- imports import(".checker") --- check the as -function _check_as(shellname) - - -- make an empty tmp.S - local tmpfile = os.tmpfile() .. ".S" - io.writefile(tmpfile, "") - - -- check it - os.run("%s -arch armv7 -o %s -c %s", shellname, os.nuldev(), tmpfile) - - -- remove this tmp.S - os.rm(tmpfile) -end - -- get toolchains function _toolchains(config) @@ -82,7 +68,7 @@ function _toolchains(config) if simulator then checker.toolchain_insert(toolchains, "as", cross, "clang", "the assember") else - checker.toolchain_insert(toolchains, "as", path.join(os.toolsdir(), "utils/gas-preprocessor.pl " .. cross), "clang", "the assember", _check_as) + checker.toolchain_insert(toolchains, "as", path.join(os.programdir(), "scripts", "gas-preprocessor.pl " .. cross), "clang", "the assember") end -- save toolchains diff --git a/xmake/platforms/windows/check.lua b/xmake/platforms/windows/check.lua index 8218ffd3a..28ad939bc 100644 --- a/xmake/platforms/windows/check.lua +++ b/xmake/platforms/windows/check.lua @@ -23,11 +23,11 @@ -- -- imports -import("core.tool.tool") -import("core.base.option") -import("platforms.checker", {rootdir = os.programdir()}) +import(".checker") import("environment") +import("core.base.option") import("detect.sdk.find_vstudio") +import("lib.detect.find_tool") -- attempt to check vs environment function _check_vsenv(config) @@ -65,7 +65,7 @@ function _check_vsenv(config) -- check compiler environment.enter("toolchains") - local toolpath = tool.check("cl.exe") + local toolpath = find_tool("cl.exe") environment.leave("toolchains") -- ok? diff --git a/xmake/scripts/gas-preprocessor.pl b/xmake/scripts/gas-preprocessor.pl new file mode 100755 index 000000000..98dfe4ad9 --- /dev/null +++ b/xmake/scripts/gas-preprocessor.pl @@ -0,0 +1,1025 @@ +#!/usr/bin/env perl +# by David Conrad +# This code is licensed under GPLv2 or later; go to gnu.org to read it +# (not that it much matters for an asm preprocessor) +# usage: set your assembler to be something like "perl gas-preprocessor.pl gcc" +use strict; + +# Apple's gas is ancient and doesn't support modern preprocessing features like +# .rept and has ugly macro syntax, among other things. Thus, this script +# implements the subset of the gas preprocessor used by x264 and ffmpeg +# that isn't supported by Apple's gas. + +my %canonical_arch = ("aarch64" => "aarch64", "arm64" => "aarch64", + "arm" => "arm", + "powerpc" => "powerpc", "ppc" => "powerpc"); + +my %comments = ("aarch64" => '//', + "arm" => '@', + "powerpc" => '#'); + +my @gcc_cmd; +my @preprocess_c_cmd; + +my $comm; +my $arch; +my $as_type = "apple-gas"; + +my $fix_unreq = $^O eq "darwin"; +my $force_thumb = 0; + +my $arm_cond_codes = "eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo"; + +my $usage_str = " +$0\n +Gas-preprocessor.pl converts assembler files using modern GNU as syntax for +Apple's ancient gas version or clang's incompatible integrated assembler. The +conversion is regularly tested for Libav, x264 and vlc. Other projects might +use different features which are not correctly handled. + +Options for this program needs to be separated with ' -- ' from the assembler +command. Following options are currently supported: + + -help - this usage text + -arch - target architecture + -as-type - one value out of {{,apple-}{gas,clang},armasm} + -fix-unreq + -no-fix-unreq + -force-thumb - assemble as thumb regardless of the input source + (note, this is incomplete and only works for sources + it explicitly was tested with) +"; + +sub usage() { + print $usage_str; +} + +while (@ARGV) { + my $opt = shift; + + if ($opt =~ /^-(no-)?fix-unreq$/) { + $fix_unreq = $1 ne "no-"; + } elsif ($opt eq "-force-thumb") { + $force_thumb = 1; + } elsif ($opt eq "-arch") { + $arch = shift; + die "unknown arch: '$arch'\n" if not exists $comments{$arch}; + } elsif ($opt eq "-as-type") { + $as_type = shift; + die "unknown as type: '$as_type'\n" if $as_type !~ /^((apple-)?(gas|clang)|armasm)$/; + } elsif ($opt eq "-help") { + usage(); + exit 0; + } elsif ($opt eq "--" ) { + @gcc_cmd = @ARGV; + } elsif ($opt =~ /^-/) { + die "option '$opt' is not known. See '$0 -help' for usage information\n"; + } else { + push @gcc_cmd, $opt, @ARGV; + } + last if (@gcc_cmd); +} + +if (grep /\.c$/, @gcc_cmd) { + # C file (inline asm?) - compile + @preprocess_c_cmd = (@gcc_cmd, "-S"); +} elsif (grep /\.[sS]$/, @gcc_cmd) { + # asm file, just do C preprocessor + @preprocess_c_cmd = (@gcc_cmd, "-E"); +} elsif (grep /-(v|-version|dumpversion)/, @gcc_cmd) { + # pass -v/--version along, used during probing. Matching '-v' might have + # uninteded results but it doesn't matter much if gas-preprocessor or + # the compiler fails. + exec(@gcc_cmd); +} else { + die "Unrecognized input filetype"; +} +if ($as_type eq "armasm") { + + $preprocess_c_cmd[0] = "cpp"; + + @preprocess_c_cmd = grep ! /^-nologo$/, @preprocess_c_cmd; + # Remove -ignore XX parameter pairs from preprocess_c_cmd + my $index = 1; + while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-ignore" and $index + 1 < $#preprocess_c_cmd) { + splice(@preprocess_c_cmd, $index, 2); + next; + } + $index++; + } + if (grep /^-MM$/, @preprocess_c_cmd) { + system(@preprocess_c_cmd) == 0 or die "Error running preprocessor"; + exit 0; + } +} + +# if compiling, avoid creating an output file named '-.o' +if ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) { + foreach my $i (@gcc_cmd) { + if ($i =~ /\.[csS]$/) { + my $outputfile = $i; + $outputfile =~ s/\.[csS]$/.o/; + push(@gcc_cmd, "-o"); + push(@gcc_cmd, $outputfile); + last; + } + } +} +# replace only the '-o' argument with '-', avoids rewriting the make dependency +# target specified with -MT to '-' +my $index = 1; +while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-o") { + $index++; + $preprocess_c_cmd[$index] = "-"; + } + $index++; +} + +my $tempfile; +if ($as_type ne "armasm") { + @gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd; +} else { + @preprocess_c_cmd = grep ! /^-c$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-m/, @preprocess_c_cmd; + + @preprocess_c_cmd = grep ! /^-G/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-W/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-Z/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-fp/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-EHsc$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-O/, @preprocess_c_cmd; + + @gcc_cmd = grep ! /^-G/, @gcc_cmd; + @gcc_cmd = grep ! /^-W/, @gcc_cmd; + @gcc_cmd = grep ! /^-Z/, @gcc_cmd; + @gcc_cmd = grep ! /^-fp/, @gcc_cmd; + @gcc_cmd = grep ! /^-EHsc$/, @gcc_cmd; + @gcc_cmd = grep ! /^-O/, @gcc_cmd; + + my @outfiles = grep /\.(o|obj)$/, @gcc_cmd; + $tempfile = $outfiles[0].".asm"; + + # Remove most parameters from gcc_cmd, which actually is the armasm command, + # which doesn't support any of the common compiler/preprocessor options. + @gcc_cmd = grep ! /^-D/, @gcc_cmd; + @gcc_cmd = grep ! /^-U/, @gcc_cmd; + @gcc_cmd = grep ! /^-m/, @gcc_cmd; + @gcc_cmd = grep ! /^-M/, @gcc_cmd; + @gcc_cmd = grep ! /^-c$/, @gcc_cmd; + @gcc_cmd = grep ! /^-I/, @gcc_cmd; + @gcc_cmd = map { /\.S$/ ? $tempfile : $_ } @gcc_cmd; +} + +# detect architecture from gcc binary name +if (!$arch) { + if ($gcc_cmd[0] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } else { + # look for -arch flag + foreach my $i (1 .. $#gcc_cmd-1) { + if ($gcc_cmd[$i] eq "-arch" and + $gcc_cmd[$i+1] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } + } + } +} + +# assume we're not cross-compiling if no -arch or the binary doesn't have the arch name +$arch = qx/arch/ if (!$arch); + +die "Unknown target architecture '$arch'" if not exists $canonical_arch{$arch}; + +$arch = $canonical_arch{$arch}; +$comm = $comments{$arch}; +my $inputcomm = $comm; +$comm = ";" if $as_type =~ /armasm/; + +my %ppc_spr = (ctr => 9, + vrsave => 256); + +open(INPUT, "-|", @preprocess_c_cmd) || die "Error running preprocessor"; + +if ($ENV{GASPP_DEBUG}) { + open(ASMFILE, ">&STDOUT"); +} else { + if ($as_type ne "armasm") { + open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler"; + } else { + open(ASMFILE, ">", $tempfile); + } +} + +my $current_macro = ''; +my $macro_level = 0; +my $rept_level = 0; +my %macro_lines; +my %macro_args; +my %macro_args_default; +my $macro_count = 0; +my $altmacro = 0; +my $in_irp = 0; + +my $num_repts; +my @rept_lines; + +my @irp_args; +my $irp_param; + +my @ifstack; + +my %symbols; + +my @sections; + +my %literal_labels; # for ldr , = +my $literal_num = 0; +my $literal_expr = ".word"; +$literal_expr = ".quad" if $arch eq "aarch64"; + +my $thumb = 0; + +my %thumb_labels; +my %call_targets; +my %mov32_targets; + +my %neon_alias_reg; +my %neon_alias_type; + +my $temp_label_next = 0; +my %last_temp_labels; +my %next_temp_labels; + +my %labels_seen; + +my %aarch64_req_alias; + +if ($force_thumb) { + parse_line(".thumb\n"); +} + +# pass 1: parse .macro +# note that the handling of arguments is probably overly permissive vs. gas +# but it should be the same for valid cases +while () { + # remove all comments (to avoid interfering with evaluating directives) + s/(? 0) { + $ifstack[-1] = -$ifstack[-1]; + } + return 1; + } elsif ($line =~ /\.else/) { + $ifstack[-1] = !$ifstack[-1]; + return 1; + } elsif (handle_if($line)) { + return 1; + } + } + + # discard lines in false .if blocks + foreach my $i (0 .. $#ifstack) { + if ($ifstack[$i] <= 0) { + return 1; + } + } + } + return 0; +} + +sub parse_line { + my $line = $_[0]; + + return if (parse_if_line($line)); + + if (scalar(@rept_lines) == 0) { + if (/\.macro/) { + $macro_level++; + if ($macro_level > 1 && !$current_macro) { + die "nested macros but we don't have master macro"; + } + } elsif (/\.endm/) { + $macro_level--; + if ($macro_level < 0) { + die "unmatched .endm"; + } elsif ($macro_level == 0) { + $current_macro = ''; + return; + } + } + } + + if ($macro_level == 0) { + if ($line =~ /\.(rept|irp)/) { + $rept_level++; + } elsif ($line =~ /.endr/) { + $rept_level--; + } + } + + if ($macro_level > 1) { + push(@{$macro_lines{$current_macro}}, $line); + } elsif (scalar(@rept_lines) and $rept_level >= 1) { + push(@rept_lines, $line); + } elsif ($macro_level == 0) { + expand_macros($line); + } else { + if ($line =~ /\.macro\s+([\d\w\.]+)\s*(.*)/) { + $current_macro = $1; + + # commas in the argument list are optional, so only use whitespace as the separator + my $arglist = $2; + $arglist =~ s/,/ /g; + + my @args = split(/\s+/, $arglist); + foreach my $i (0 .. $#args) { + my @argpair = split(/=/, $args[$i]); + $macro_args{$current_macro}[$i] = $argpair[0]; + $argpair[0] =~ s/:vararg$//; + $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1]; + } + # ensure %macro_lines has the macro name added as a key + $macro_lines{$current_macro} = []; + + } elsif ($current_macro) { + push(@{$macro_lines{$current_macro}}, $line); + } else { + die "macro level without a macro name"; + } + } +} + +sub handle_set { + my $line = $_[0]; + if ($line =~ /\.set\s+(.*),\s*(.*)/) { + $symbols{$1} = eval_expr($2); + return 1; + } + return 0; +} + +sub expand_macros { + my $line = $_[0]; + + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if (handle_if($line)) { + return; + } + + if (/\.purgem\s+([\d\w\.]+)/) { + delete $macro_lines{$1}; + delete $macro_args{$1}; + delete $macro_args_default{$1}; + return; + } + + if ($line =~ /\.altmacro/) { + $altmacro = 1; + return; + } + + if ($line =~ /\.noaltmacro/) { + $altmacro = 0; + return; + } + + $line =~ s/\%([^,]*)/eval_expr($1)/eg if $altmacro; + + # Strip out the .set lines from the armasm output + return if (handle_set($line) and $as_type eq "armasm"); + + if ($line =~ /\.rept\s+(.*)/) { + $num_repts = $1; + @rept_lines = ("\n"); + + # handle the possibility of repeating another directive on the same line + # .endr on the same line is not valid, I don't know if a non-directive is + if ($num_repts =~ s/(\.\w+.*)//) { + push(@rept_lines, "$1\n"); + } + $num_repts = eval_expr($num_repts); + } elsif ($line =~ /\.irp\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + # only use whitespace as the separator + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(/\s+/, $irp_arglist); + } elsif ($line =~ /\.irpc\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(//, $irp_arglist); + } elsif ($line =~ /\.endr/) { + my @prev_rept_lines = @rept_lines; + my $prev_in_irp = $in_irp; + my @prev_irp_args = @irp_args; + my $prev_irp_param = $irp_param; + my $prev_num_repts = $num_repts; + @rept_lines = (); + $in_irp = 0; + @irp_args = ''; + + if ($prev_in_irp != 0) { + foreach my $i (@prev_irp_args) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + $line =~ s/\\$prev_irp_param/$i/g; + $line =~ s/\\\(\)//g; # remove \() + parse_line($line); + } + } + } else { + for (1 .. $prev_num_repts) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + parse_line($line); + } + } + } + } elsif ($line =~ /(\S+:|)\s*([\w\d\.]+)\s*(.*)/ && exists $macro_lines{$2}) { + handle_serialized_line($1); + my $macro = $2; + + # commas are optional here too, but are syntactically important because + # parameters can be blank + my @arglist = split(/,/, $3); + my @args; + my @args_seperator; + + my $comma_sep_required = 0; + foreach (@arglist) { + # allow arithmetic/shift operators in macro arguments + $_ =~ s/\s*(\+|-|\*|\/|<<|>>|<|>)\s*/$1/g; + + my @whitespace_split = split(/\s+/, $_); + if (!@whitespace_split) { + push(@args, ''); + push(@args_seperator, ''); + } else { + foreach (@whitespace_split) { + #print ("arglist = \"$_\"\n"); + if (length($_)) { + push(@args, $_); + my $sep = $comma_sep_required ? "," : " "; + push(@args_seperator, $sep); + #print ("sep = \"$sep\", arg = \"$_\"\n"); + $comma_sep_required = 0; + } + } + } + + $comma_sep_required = 1; + } + + my %replacements; + if ($macro_args_default{$macro}){ + %replacements = %{$macro_args_default{$macro}}; + } + + # construct hashtable of text to replace + foreach my $i (0 .. $#args) { + my $argname = $macro_args{$macro}[$i]; + my @macro_args = @{ $macro_args{$macro} }; + if ($args[$i] =~ m/=/) { + # arg=val references the argument name + # XXX: I'm not sure what the expected behaviour if a lot of + # these are mixed with unnamed args + my @named_arg = split(/=/, $args[$i]); + $replacements{$named_arg[0]} = $named_arg[1]; + } elsif ($i > $#{$macro_args{$macro}}) { + # more args given than the macro has named args + # XXX: is vararg allowed on arguments before the last? + $argname = $macro_args{$macro}[-1]; + if ($argname =~ s/:vararg$//) { + #print "macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\n"; + #$replacements{$argname} .= ", $args[$i]"; + $replacements{$argname} .= "$args_seperator[$i] $args[$i]"; + } else { + die "Too many arguments to macro $macro"; + } + } else { + $argname =~ s/:vararg$//; + $replacements{$argname} = $args[$i]; + } + } + + my $count = $macro_count++; + + # apply replacements as regex + foreach (@{$macro_lines{$macro}}) { + my $macro_line = $_; + # do replacements by longest first, this avoids wrong replacement + # when argument names are subsets of each other + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\\$_/$replacements{$_}/g; + } + if ($altmacro) { + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\b$_\b/$replacements{$_}/g; + } + } + $macro_line =~ s/\\\@/$count/g; + $macro_line =~ s/\\\(\)//g; # remove \() + parse_line($macro_line); + } + } else { + handle_serialized_line($line); + } +} + +sub is_arm_register { + my $name = $_[0]; + if ($name eq "lr" or + $name eq "ip" or + $name =~ /^[rav]\d+$/) { + return 1; + } + return 0; +} + +sub handle_local_label { + my $line = $_[0]; + my $num = $_[1]; + my $dir = $_[2]; + my $target = "$num$dir"; + if ($dir eq "b") { + $line =~ s/$target/$last_temp_labels{$num}/g; + } else { + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + push(@{$next_temp_labels{$num}}, $name); + $line =~ s/$target/$name/g; + } + return $line; +} + +sub handle_serialized_line { + my $line = $_[0]; + + # handle .previous (only with regard to .section not .subsection) + if ($line =~ /\.(section|text|const_data)/) { + push(@sections, $line); + } elsif ($line =~ /\.previous/) { + if (!$sections[-2]) { + die ".previous without a previous section"; + } + $line = $sections[-2]; + push(@sections, $line); + } + + $thumb = 1 if $line =~ /\.code\s+16|\.thumb/; + $thumb = 0 if $line =~ /\.code\s+32|\.arm/; + + # handle ldr , = + if ($line =~ /(.*)\s*ldr([\w\s\d]+)\s*,\s*=(.*)/ and $as_type ne "armasm") { + my $label = $literal_labels{$3}; + if (!$label) { + $label = "Literal_$literal_num"; + $literal_num++; + $literal_labels{$3} = $label; + } + $line = "$1 ldr$2, $label\n"; + } elsif ($line =~ /\.ltorg/ and $as_type ne "armasm") { + $line .= ".align 2\n"; + foreach my $literal (keys %literal_labels) { + $line .= "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + %literal_labels = (); + } + + # handle GNU as pc-relative relocations for adrp/add + if ($line =~ /(.*)\s*adrp([\w\s\d]+)\s*,\s*#?:pg_hi21:([^\s]+)/) { + $line = "$1 adrp$2, ${3}\@PAGE\n"; + } elsif ($line =~ /(.*)\s*add([\w\s\d]+)\s*,([\w\s\d]+)\s*,\s*#?:lo12:([^\s]+)/) { + $line = "$1 add$2, $3, ${4}\@PAGEOFF\n"; + } + + # thumb add with large immediate needs explicit add.w + if ($thumb and $line =~ /add\s+.*#([^@]+)/) { + $line =~ s/add/add.w/ if eval_expr($1) > 255; + } + + # mach-o local symbol names start with L (no dot) + $line =~ s/(? with ic as conditional code + if ($cond =~ /|$arm_cond_codes/) { + if (exists $thumb_labels{$label}) { + print ASMFILE ".thumb_func $label\n"; + } else { + $call_targets{$label}++; + } + } + } + + # @l -> lo16() @ha -> ha16() + $line =~ s/,\s+([^,]+)\@l\b/, lo16($1)/g; + $line =~ s/,\s+([^,]+)\@ha\b/, ha16($1)/g; + + # move to/from SPR + if ($line =~ /(\s+)(m[ft])([a-z]+)\s+(\w+)/ and exists $ppc_spr{$3}) { + if ($2 eq 'mt') { + $line = "$1${2}spr $ppc_spr{$3}, $4\n"; + } else { + $line = "$1${2}spr $4, $ppc_spr{$3}\n"; + } + } + + if ($line =~ /\.unreq\s+(.*)/) { + if (defined $neon_alias_reg{$1}) { + delete $neon_alias_reg{$1}; + delete $neon_alias_type{$1}; + return; + } elsif (defined $aarch64_req_alias{$1}) { + delete $aarch64_req_alias{$1}; + return; + } + } + # old gas versions store upper and lower case names on .req, + # but they remove only one on .unreq + if ($fix_unreq) { + if ($line =~ /\.unreq\s+(.*)/) { + $line = ".unreq " . lc($1) . "\n"; + $line .= ".unreq " . uc($1) . "\n"; + } + } + + if ($line =~ /(\w+)\s+\.(dn|qn)\s+(\w+)(?:\.(\w+))?(\[\d+\])?/) { + $neon_alias_reg{$1} = "$3$5"; + $neon_alias_type{$1} = $4; + return; + } + if (scalar keys %neon_alias_reg > 0 && $line =~ /^\s+v\w+/) { + # This line seems to possibly have a neon instruction + foreach (keys %neon_alias_reg) { + my $alias = $_; + # Require the register alias to match as an invididual word, not as a substring + # of a larger word-token. + if ($line =~ /\b$alias\b/) { + $line =~ s/\b$alias\b/$neon_alias_reg{$alias}/g; + # Add the type suffix. If multiple aliases match on the same line, + # only do this replacement the first time (a vfoo.bar string won't match v\w+). + $line =~ s/^(\s+)(v\w+)(\s+)/$1$2.$neon_alias_type{$alias}$3/; + } + } + } + + if ($arch eq "aarch64" or $as_type eq "armasm") { + # clang's integrated aarch64 assembler in Xcode 5 does not support .req/.unreq + if ($line =~ /\b(\w+)\s+\.req\s+(\w+)\b/) { + $aarch64_req_alias{$1} = $2; + return; + } + foreach (keys %aarch64_req_alias) { + my $alias = $_; + # recursively resolve aliases + my $resolved = $aarch64_req_alias{$alias}; + while (defined $aarch64_req_alias{$resolved}) { + $resolved = $aarch64_req_alias{$resolved}; + } + $line =~ s/\b$alias\b/$resolved/g; + } + } + if ($arch eq "aarch64") { + # fix missing aarch64 instructions in Xcode 5.1 (beta3) + # mov with vector arguments is not supported, use alias orr instead + if ($line =~ /^\s*mov\s+(v\d[\.{}\[\]\w]+),\s*(v\d[\.{}\[\]\w]+)\b\s*$/) { + $line = " orr $1, $2, $2\n"; + } + # movi 16, 32 bit shifted variant, shift is optional + if ($line =~ /^\s*movi\s+(v[0-3]?\d\.(?:2|4|8)[hsHS])\s*,\s*(#\w+)\b\s*$/) { + $line = " movi $1, $2, lsl #0\n"; + } + # Xcode 5 misses the alias uxtl. Replace it with the more general ushll. + # Clang 3.4 misses the alias sxtl too. Replace it with the more general sshll. + if ($line =~ /^\s*(s|u)xtl(2)?\s+(v[0-3]?\d\.[248][hsdHSD])\s*,\s*(v[0-3]?\d\.(?:2|4|8|16)[bhsBHS])\b\s*$/) { + $line = " $1shll$2 $3, $4, #0\n"; + } + # clang 3.4 does not automatically use shifted immediates in add/sub + if ($as_type eq "clang" and + $line =~ /^(\s*(?:add|sub)s?) ([^#l]+)#([\d\+\-\*\/ <>]+)\s*$/) { + my $imm = eval $3; + if ($imm > 4095 and not ($imm & 4095)) { + $line = "$1 $2#" . ($imm >> 12) . ", lsl #12\n"; + } + } + if ($ENV{GASPP_FIX_XCODE5}) { + if ($line =~ /^\s*bsl\b/) { + $line =~ s/\b(bsl)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.$3\b/$1/g; + } + if ($line =~ /^\s*saddl2?\b/) { + $line =~ s/\b(saddl2?)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.\w+\b/$1/g; + } + if ($line =~ /^\s*dup\b.*\]$/) { + $line =~ s/\bdup(\s+v[0-3]?\d)\.(\w+)\b/dup.$2$1/g; + $line =~ s/\b(v[0-3]?\d)\.[bhsdBHSD](\[\d\])$/$1$2/g; + } + } + } + + if ($as_type eq "armasm") { + # Also replace variables set by .set + foreach (keys %symbols) { + my $sym = $_; + $line =~ s/\b$sym\b/$symbols{$sym}/g; + } + + # Handle function declarations and keep track of the declared labels + if ($line =~ s/^\s*\.func\s+(\w+)/$1 PROC/) { + $labels_seen{$1} = 1; + } + + if ($line =~ s/^(\d+)://) { + # Convert local labels into unique labels. armasm (at least in + # RVCT) has something similar, but still different enough. + # By converting to unique labels we avoid any possible + # incompatibilities. + + my $num = $1; + foreach (@{$next_temp_labels{$num}}) { + $line = "$_\n" . $line; + } + @next_temp_labels{$num} = (); + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + # The matching regexp above removes the label from the start of + # the line (which might contain an instruction as well), readd + # it on a separate line above it. + $line = "$name:\n" . $line; + $last_temp_labels{$num} = $name; + } + + if ($line =~ s/^(\w+):/$1/) { + # Skip labels that have already been declared with a PROC, + # labels must not be declared multiple times. + return if (defined $labels_seen{$1}); + $labels_seen{$1} = 1; + } elsif ($line !~ /(\w+) PROC/) { + # If not a label, make sure the line starts with whitespace, + # otherwise ms armasm interprets it incorrectly. + $line =~ s/^[\.\w]/\t$&/; + } + + + # Check branch instructions + if ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(bl?x?(..)?(\.w)?)\s+(\w+)/) { + my $instr = $2; + my $cond = $3; + my $width = $4; + my $target = $5; + # Don't interpret e.g. bic as b with ic as conditional code + if ($cond !~ /|$arm_cond_codes/) { + # Not actually a branch + } elsif ($target =~ /(\d+)([bf])/) { + # The target is a local label + $line = handle_local_label($line, $1, $2); + $line =~ s/\b$instr\b/$&.w/ if $width eq ""; + } elsif (!is_arm_register($target)) { + $call_targets{$target}++; + } + } elsif ($line =~ /^\s*.h?word.*\b\d+[bf]\b/) { + while ($line =~ /\b(\d+)([bf])\b/g) { + $line = handle_local_label($line, $1, $2); + } + } + + # ALIGN in armasm syntax is the actual number of bytes + if ($line =~ /\.align\s+(\d+)/) { + my $align = 1 << $1; + $line =~ s/\.align\s(\d+)/ALIGN $align/; + } + # Convert gas style [r0, :128] into armasm [r0@128] alignment specification + $line =~ s/\[([^\[]+),\s*:(\d+)\]/[$1\@$2]/g; + + # armasm treats logical values {TRUE} and {FALSE} separately from + # numeric values - logical operators and values can't be intermixed + # with numerical values. Evaluate ! and (a <> b) into numbers, + # let the assembler evaluate the rest of the expressions. This current + # only works for cases when ! and <> are used with actual constant numbers, + # we don't evaluate subexpressions here. + + # Evaluate ! + while ($line =~ /!\s*(\d+)/g) { + my $val = ($1 != 0) ? 0 : 1; + $line =~ s/!(\d+)/$val/; + } + # Evaluate (a > b) + while ($line =~ /\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/) { + my $val; + if ($2 eq "<") { + $val = ($1 < $3) ? 1 : 0; + } else { + $val = ($1 > $3) ? 1 : 0; + } + $line =~ s/\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/$val/; + } + + # Change a movw... #:lower16: into a mov32 pseudoinstruction + $line =~ s/^(\s*)movw(\s+\w+\s*,\s*)\#:lower16:(.*)$/$1mov32$2$3/; + # and remove the following, matching movt completely + $line =~ s/^\s*movt\s+\w+\s*,\s*\#:upper16:.*$//; + + if ($line =~ /^\s*mov32\s+\w+,\s*([a-zA-Z]\w*)/) { + $mov32_targets{$1}++; + } + + # Misc bugs/deficiencies: + # armasm seems unable to parse e.g. "vmov s0, s1" without a type + # qualifier, thus add .f32. + $line =~ s/^(\s+(?:vmov|vadd))(\s+s)/$1.f32$2/; + # armasm is unable to parse &0x - add spacing + $line =~ s/&0x/& 0x/g; + } + + if ($force_thumb) { + # Convert register post indexing to a separate add instruction. + # This converts e.g. "ldr r0, [r1], r2" into "ldr r0, [r1]", + # "add r1, r1, r2". + $line =~ s/(ldr|str)\s+(\w+),\s*\[(\w+)\],\s*(\w+)/$1 $2, [$3]\n\tadd $3, $3, $4/g; + + # Convert "mov pc, lr" into "bx lr", since the former only works + # for switching from arm to thumb (and only in armv7), but not + # from thumb to arm. + s/mov\s*pc\s*,\s*lr/bx lr/g; + + # Convert stmdb/ldmia with only one register into a plain str/ldr with post-increment/decrement + $line =~ s/stmdb\s+sp!\s*,\s*\{([^,-]+)\}/str $1, [sp, #-4]!/g; + $line =~ s/ldmia\s+sp!\s*,\s*\{([^,-]+)\}/ldr $1, [sp], #4/g; + + $line =~ s/\.arm/.thumb/x; + } + + # comment out unsupported directives + $line =~ s/\.type/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.func/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/ENDP/x if $as_type =~ /armasm/; + $line =~ s/\.ltorg/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.ltorg/LTORG/x if $as_type eq "armasm"; + $line =~ s/\.size/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.fpu/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.arch/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; + $line =~ s/\.object_arch/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/.section\s+.note.GNU-stack.*/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.hidden/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; + + $line =~ s/\.syntax/$comm$&/x if $as_type =~ /armasm/; + + $line =~ s/\.hword/.short/x; + + if ($as_type =~ /^apple-/) { + # the syntax for these is a little different + $line =~ s/\.global/.globl/x; + # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const + $line =~ s/(.*)\.rodata/.const_data/x; + $line =~ s/\.int/.long/x; + $line =~ s/\.float/.single/x; + } + if ($as_type eq "armasm") { + $line =~ s/\.global/EXPORT/x; + $line =~ s/\.int/dcd/x; + $line =~ s/\.long/dcd/x; + $line =~ s/\.float/dcfs/x; + $line =~ s/\.word/dcd/x; + $line =~ s/\.short/dcw/x; + $line =~ s/\.byte/dcb/x; + $line =~ s/\.thumb/THUMB/x; + $line =~ s/\.arm/ARM/x; + # The alignment in AREA is the power of two, just as .align in gas + $line =~ s/\.text/AREA |.text|, CODE, READONLY, ALIGN=2, CODEALIGN/; + $line =~ s/(\s*)(.*)\.rodata/$1AREA |.rodata|, DATA, READONLY, ALIGN=5/; + + $line =~ s/fmxr/vmsr/; + $line =~ s/fmrx/vmrs/; + $line =~ s/fadds/vadd/; + } + + # catch unknown section names that aren't mach-o style (with a comma) + if ($as_type =~ /apple-/ and $line =~ /.section ([^,]*)$/) { + die ".section $1 unsupported; figure out the mach-o section name and add it"; + } + + print ASMFILE $line; +} + +if ($as_type ne "armasm") { + print ASMFILE ".text\n"; + print ASMFILE ".align 2\n"; + foreach my $literal (keys %literal_labels) { + print ASMFILE "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + + map print(ASMFILE ".thumb_func $_\n"), + grep exists $thumb_labels{$_}, keys %call_targets; +} else { + map print(ASMFILE "\tIMPORT $_\n"), + grep ! exists $labels_seen{$_}, (keys %call_targets, keys %mov32_targets); + + print ASMFILE "\tEND\n"; +} + +close(INPUT) or exit 1; +close(ASMFILE) or exit 1; +if ($as_type eq "armasm" and ! defined $ENV{GASPP_DEBUG}) { + system(@gcc_cmd) == 0 or die "Error running assembler"; +} + +END { + unlink($tempfile) if defined $tempfile; +} +#exit 1 diff --git a/xmake/tools/utils/gas-preprocessor.pl b/xmake/tools/utils/gas-preprocessor.pl deleted file mode 100755 index 98dfe4ad9..000000000 --- a/xmake/tools/utils/gas-preprocessor.pl +++ /dev/null @@ -1,1025 +0,0 @@ -#!/usr/bin/env perl -# by David Conrad -# This code is licensed under GPLv2 or later; go to gnu.org to read it -# (not that it much matters for an asm preprocessor) -# usage: set your assembler to be something like "perl gas-preprocessor.pl gcc" -use strict; - -# Apple's gas is ancient and doesn't support modern preprocessing features like -# .rept and has ugly macro syntax, among other things. Thus, this script -# implements the subset of the gas preprocessor used by x264 and ffmpeg -# that isn't supported by Apple's gas. - -my %canonical_arch = ("aarch64" => "aarch64", "arm64" => "aarch64", - "arm" => "arm", - "powerpc" => "powerpc", "ppc" => "powerpc"); - -my %comments = ("aarch64" => '//', - "arm" => '@', - "powerpc" => '#'); - -my @gcc_cmd; -my @preprocess_c_cmd; - -my $comm; -my $arch; -my $as_type = "apple-gas"; - -my $fix_unreq = $^O eq "darwin"; -my $force_thumb = 0; - -my $arm_cond_codes = "eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo"; - -my $usage_str = " -$0\n -Gas-preprocessor.pl converts assembler files using modern GNU as syntax for -Apple's ancient gas version or clang's incompatible integrated assembler. The -conversion is regularly tested for Libav, x264 and vlc. Other projects might -use different features which are not correctly handled. - -Options for this program needs to be separated with ' -- ' from the assembler -command. Following options are currently supported: - - -help - this usage text - -arch - target architecture - -as-type - one value out of {{,apple-}{gas,clang},armasm} - -fix-unreq - -no-fix-unreq - -force-thumb - assemble as thumb regardless of the input source - (note, this is incomplete and only works for sources - it explicitly was tested with) -"; - -sub usage() { - print $usage_str; -} - -while (@ARGV) { - my $opt = shift; - - if ($opt =~ /^-(no-)?fix-unreq$/) { - $fix_unreq = $1 ne "no-"; - } elsif ($opt eq "-force-thumb") { - $force_thumb = 1; - } elsif ($opt eq "-arch") { - $arch = shift; - die "unknown arch: '$arch'\n" if not exists $comments{$arch}; - } elsif ($opt eq "-as-type") { - $as_type = shift; - die "unknown as type: '$as_type'\n" if $as_type !~ /^((apple-)?(gas|clang)|armasm)$/; - } elsif ($opt eq "-help") { - usage(); - exit 0; - } elsif ($opt eq "--" ) { - @gcc_cmd = @ARGV; - } elsif ($opt =~ /^-/) { - die "option '$opt' is not known. See '$0 -help' for usage information\n"; - } else { - push @gcc_cmd, $opt, @ARGV; - } - last if (@gcc_cmd); -} - -if (grep /\.c$/, @gcc_cmd) { - # C file (inline asm?) - compile - @preprocess_c_cmd = (@gcc_cmd, "-S"); -} elsif (grep /\.[sS]$/, @gcc_cmd) { - # asm file, just do C preprocessor - @preprocess_c_cmd = (@gcc_cmd, "-E"); -} elsif (grep /-(v|-version|dumpversion)/, @gcc_cmd) { - # pass -v/--version along, used during probing. Matching '-v' might have - # uninteded results but it doesn't matter much if gas-preprocessor or - # the compiler fails. - exec(@gcc_cmd); -} else { - die "Unrecognized input filetype"; -} -if ($as_type eq "armasm") { - - $preprocess_c_cmd[0] = "cpp"; - - @preprocess_c_cmd = grep ! /^-nologo$/, @preprocess_c_cmd; - # Remove -ignore XX parameter pairs from preprocess_c_cmd - my $index = 1; - while ($index < $#preprocess_c_cmd) { - if ($preprocess_c_cmd[$index] eq "-ignore" and $index + 1 < $#preprocess_c_cmd) { - splice(@preprocess_c_cmd, $index, 2); - next; - } - $index++; - } - if (grep /^-MM$/, @preprocess_c_cmd) { - system(@preprocess_c_cmd) == 0 or die "Error running preprocessor"; - exit 0; - } -} - -# if compiling, avoid creating an output file named '-.o' -if ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) { - foreach my $i (@gcc_cmd) { - if ($i =~ /\.[csS]$/) { - my $outputfile = $i; - $outputfile =~ s/\.[csS]$/.o/; - push(@gcc_cmd, "-o"); - push(@gcc_cmd, $outputfile); - last; - } - } -} -# replace only the '-o' argument with '-', avoids rewriting the make dependency -# target specified with -MT to '-' -my $index = 1; -while ($index < $#preprocess_c_cmd) { - if ($preprocess_c_cmd[$index] eq "-o") { - $index++; - $preprocess_c_cmd[$index] = "-"; - } - $index++; -} - -my $tempfile; -if ($as_type ne "armasm") { - @gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd; -} else { - @preprocess_c_cmd = grep ! /^-c$/, @preprocess_c_cmd; - @preprocess_c_cmd = grep ! /^-m/, @preprocess_c_cmd; - - @preprocess_c_cmd = grep ! /^-G/, @preprocess_c_cmd; - @preprocess_c_cmd = grep ! /^-W/, @preprocess_c_cmd; - @preprocess_c_cmd = grep ! /^-Z/, @preprocess_c_cmd; - @preprocess_c_cmd = grep ! /^-fp/, @preprocess_c_cmd; - @preprocess_c_cmd = grep ! /^-EHsc$/, @preprocess_c_cmd; - @preprocess_c_cmd = grep ! /^-O/, @preprocess_c_cmd; - - @gcc_cmd = grep ! /^-G/, @gcc_cmd; - @gcc_cmd = grep ! /^-W/, @gcc_cmd; - @gcc_cmd = grep ! /^-Z/, @gcc_cmd; - @gcc_cmd = grep ! /^-fp/, @gcc_cmd; - @gcc_cmd = grep ! /^-EHsc$/, @gcc_cmd; - @gcc_cmd = grep ! /^-O/, @gcc_cmd; - - my @outfiles = grep /\.(o|obj)$/, @gcc_cmd; - $tempfile = $outfiles[0].".asm"; - - # Remove most parameters from gcc_cmd, which actually is the armasm command, - # which doesn't support any of the common compiler/preprocessor options. - @gcc_cmd = grep ! /^-D/, @gcc_cmd; - @gcc_cmd = grep ! /^-U/, @gcc_cmd; - @gcc_cmd = grep ! /^-m/, @gcc_cmd; - @gcc_cmd = grep ! /^-M/, @gcc_cmd; - @gcc_cmd = grep ! /^-c$/, @gcc_cmd; - @gcc_cmd = grep ! /^-I/, @gcc_cmd; - @gcc_cmd = map { /\.S$/ ? $tempfile : $_ } @gcc_cmd; -} - -# detect architecture from gcc binary name -if (!$arch) { - if ($gcc_cmd[0] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { - $arch = $1; - } else { - # look for -arch flag - foreach my $i (1 .. $#gcc_cmd-1) { - if ($gcc_cmd[$i] eq "-arch" and - $gcc_cmd[$i+1] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { - $arch = $1; - } - } - } -} - -# assume we're not cross-compiling if no -arch or the binary doesn't have the arch name -$arch = qx/arch/ if (!$arch); - -die "Unknown target architecture '$arch'" if not exists $canonical_arch{$arch}; - -$arch = $canonical_arch{$arch}; -$comm = $comments{$arch}; -my $inputcomm = $comm; -$comm = ";" if $as_type =~ /armasm/; - -my %ppc_spr = (ctr => 9, - vrsave => 256); - -open(INPUT, "-|", @preprocess_c_cmd) || die "Error running preprocessor"; - -if ($ENV{GASPP_DEBUG}) { - open(ASMFILE, ">&STDOUT"); -} else { - if ($as_type ne "armasm") { - open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler"; - } else { - open(ASMFILE, ">", $tempfile); - } -} - -my $current_macro = ''; -my $macro_level = 0; -my $rept_level = 0; -my %macro_lines; -my %macro_args; -my %macro_args_default; -my $macro_count = 0; -my $altmacro = 0; -my $in_irp = 0; - -my $num_repts; -my @rept_lines; - -my @irp_args; -my $irp_param; - -my @ifstack; - -my %symbols; - -my @sections; - -my %literal_labels; # for ldr , = -my $literal_num = 0; -my $literal_expr = ".word"; -$literal_expr = ".quad" if $arch eq "aarch64"; - -my $thumb = 0; - -my %thumb_labels; -my %call_targets; -my %mov32_targets; - -my %neon_alias_reg; -my %neon_alias_type; - -my $temp_label_next = 0; -my %last_temp_labels; -my %next_temp_labels; - -my %labels_seen; - -my %aarch64_req_alias; - -if ($force_thumb) { - parse_line(".thumb\n"); -} - -# pass 1: parse .macro -# note that the handling of arguments is probably overly permissive vs. gas -# but it should be the same for valid cases -while () { - # remove all comments (to avoid interfering with evaluating directives) - s/(? 0) { - $ifstack[-1] = -$ifstack[-1]; - } - return 1; - } elsif ($line =~ /\.else/) { - $ifstack[-1] = !$ifstack[-1]; - return 1; - } elsif (handle_if($line)) { - return 1; - } - } - - # discard lines in false .if blocks - foreach my $i (0 .. $#ifstack) { - if ($ifstack[$i] <= 0) { - return 1; - } - } - } - return 0; -} - -sub parse_line { - my $line = $_[0]; - - return if (parse_if_line($line)); - - if (scalar(@rept_lines) == 0) { - if (/\.macro/) { - $macro_level++; - if ($macro_level > 1 && !$current_macro) { - die "nested macros but we don't have master macro"; - } - } elsif (/\.endm/) { - $macro_level--; - if ($macro_level < 0) { - die "unmatched .endm"; - } elsif ($macro_level == 0) { - $current_macro = ''; - return; - } - } - } - - if ($macro_level == 0) { - if ($line =~ /\.(rept|irp)/) { - $rept_level++; - } elsif ($line =~ /.endr/) { - $rept_level--; - } - } - - if ($macro_level > 1) { - push(@{$macro_lines{$current_macro}}, $line); - } elsif (scalar(@rept_lines) and $rept_level >= 1) { - push(@rept_lines, $line); - } elsif ($macro_level == 0) { - expand_macros($line); - } else { - if ($line =~ /\.macro\s+([\d\w\.]+)\s*(.*)/) { - $current_macro = $1; - - # commas in the argument list are optional, so only use whitespace as the separator - my $arglist = $2; - $arglist =~ s/,/ /g; - - my @args = split(/\s+/, $arglist); - foreach my $i (0 .. $#args) { - my @argpair = split(/=/, $args[$i]); - $macro_args{$current_macro}[$i] = $argpair[0]; - $argpair[0] =~ s/:vararg$//; - $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1]; - } - # ensure %macro_lines has the macro name added as a key - $macro_lines{$current_macro} = []; - - } elsif ($current_macro) { - push(@{$macro_lines{$current_macro}}, $line); - } else { - die "macro level without a macro name"; - } - } -} - -sub handle_set { - my $line = $_[0]; - if ($line =~ /\.set\s+(.*),\s*(.*)/) { - $symbols{$1} = eval_expr($2); - return 1; - } - return 0; -} - -sub expand_macros { - my $line = $_[0]; - - # handle .if directives; apple's assembler doesn't support important non-basic ones - # evaluating them is also needed to handle recursive macros - if (handle_if($line)) { - return; - } - - if (/\.purgem\s+([\d\w\.]+)/) { - delete $macro_lines{$1}; - delete $macro_args{$1}; - delete $macro_args_default{$1}; - return; - } - - if ($line =~ /\.altmacro/) { - $altmacro = 1; - return; - } - - if ($line =~ /\.noaltmacro/) { - $altmacro = 0; - return; - } - - $line =~ s/\%([^,]*)/eval_expr($1)/eg if $altmacro; - - # Strip out the .set lines from the armasm output - return if (handle_set($line) and $as_type eq "armasm"); - - if ($line =~ /\.rept\s+(.*)/) { - $num_repts = $1; - @rept_lines = ("\n"); - - # handle the possibility of repeating another directive on the same line - # .endr on the same line is not valid, I don't know if a non-directive is - if ($num_repts =~ s/(\.\w+.*)//) { - push(@rept_lines, "$1\n"); - } - $num_repts = eval_expr($num_repts); - } elsif ($line =~ /\.irp\s+([\d\w\.]+)\s*(.*)/) { - $in_irp = 1; - $num_repts = 1; - @rept_lines = ("\n"); - $irp_param = $1; - - # only use whitespace as the separator - my $irp_arglist = $2; - $irp_arglist =~ s/,/ /g; - $irp_arglist =~ s/^\s+//; - @irp_args = split(/\s+/, $irp_arglist); - } elsif ($line =~ /\.irpc\s+([\d\w\.]+)\s*(.*)/) { - $in_irp = 1; - $num_repts = 1; - @rept_lines = ("\n"); - $irp_param = $1; - - my $irp_arglist = $2; - $irp_arglist =~ s/,/ /g; - $irp_arglist =~ s/^\s+//; - @irp_args = split(//, $irp_arglist); - } elsif ($line =~ /\.endr/) { - my @prev_rept_lines = @rept_lines; - my $prev_in_irp = $in_irp; - my @prev_irp_args = @irp_args; - my $prev_irp_param = $irp_param; - my $prev_num_repts = $num_repts; - @rept_lines = (); - $in_irp = 0; - @irp_args = ''; - - if ($prev_in_irp != 0) { - foreach my $i (@prev_irp_args) { - foreach my $origline (@prev_rept_lines) { - my $line = $origline; - $line =~ s/\\$prev_irp_param/$i/g; - $line =~ s/\\\(\)//g; # remove \() - parse_line($line); - } - } - } else { - for (1 .. $prev_num_repts) { - foreach my $origline (@prev_rept_lines) { - my $line = $origline; - parse_line($line); - } - } - } - } elsif ($line =~ /(\S+:|)\s*([\w\d\.]+)\s*(.*)/ && exists $macro_lines{$2}) { - handle_serialized_line($1); - my $macro = $2; - - # commas are optional here too, but are syntactically important because - # parameters can be blank - my @arglist = split(/,/, $3); - my @args; - my @args_seperator; - - my $comma_sep_required = 0; - foreach (@arglist) { - # allow arithmetic/shift operators in macro arguments - $_ =~ s/\s*(\+|-|\*|\/|<<|>>|<|>)\s*/$1/g; - - my @whitespace_split = split(/\s+/, $_); - if (!@whitespace_split) { - push(@args, ''); - push(@args_seperator, ''); - } else { - foreach (@whitespace_split) { - #print ("arglist = \"$_\"\n"); - if (length($_)) { - push(@args, $_); - my $sep = $comma_sep_required ? "," : " "; - push(@args_seperator, $sep); - #print ("sep = \"$sep\", arg = \"$_\"\n"); - $comma_sep_required = 0; - } - } - } - - $comma_sep_required = 1; - } - - my %replacements; - if ($macro_args_default{$macro}){ - %replacements = %{$macro_args_default{$macro}}; - } - - # construct hashtable of text to replace - foreach my $i (0 .. $#args) { - my $argname = $macro_args{$macro}[$i]; - my @macro_args = @{ $macro_args{$macro} }; - if ($args[$i] =~ m/=/) { - # arg=val references the argument name - # XXX: I'm not sure what the expected behaviour if a lot of - # these are mixed with unnamed args - my @named_arg = split(/=/, $args[$i]); - $replacements{$named_arg[0]} = $named_arg[1]; - } elsif ($i > $#{$macro_args{$macro}}) { - # more args given than the macro has named args - # XXX: is vararg allowed on arguments before the last? - $argname = $macro_args{$macro}[-1]; - if ($argname =~ s/:vararg$//) { - #print "macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\n"; - #$replacements{$argname} .= ", $args[$i]"; - $replacements{$argname} .= "$args_seperator[$i] $args[$i]"; - } else { - die "Too many arguments to macro $macro"; - } - } else { - $argname =~ s/:vararg$//; - $replacements{$argname} = $args[$i]; - } - } - - my $count = $macro_count++; - - # apply replacements as regex - foreach (@{$macro_lines{$macro}}) { - my $macro_line = $_; - # do replacements by longest first, this avoids wrong replacement - # when argument names are subsets of each other - foreach (reverse sort {length $a <=> length $b} keys %replacements) { - $macro_line =~ s/\\$_/$replacements{$_}/g; - } - if ($altmacro) { - foreach (reverse sort {length $a <=> length $b} keys %replacements) { - $macro_line =~ s/\b$_\b/$replacements{$_}/g; - } - } - $macro_line =~ s/\\\@/$count/g; - $macro_line =~ s/\\\(\)//g; # remove \() - parse_line($macro_line); - } - } else { - handle_serialized_line($line); - } -} - -sub is_arm_register { - my $name = $_[0]; - if ($name eq "lr" or - $name eq "ip" or - $name =~ /^[rav]\d+$/) { - return 1; - } - return 0; -} - -sub handle_local_label { - my $line = $_[0]; - my $num = $_[1]; - my $dir = $_[2]; - my $target = "$num$dir"; - if ($dir eq "b") { - $line =~ s/$target/$last_temp_labels{$num}/g; - } else { - my $name = "temp_label_$temp_label_next"; - $temp_label_next++; - push(@{$next_temp_labels{$num}}, $name); - $line =~ s/$target/$name/g; - } - return $line; -} - -sub handle_serialized_line { - my $line = $_[0]; - - # handle .previous (only with regard to .section not .subsection) - if ($line =~ /\.(section|text|const_data)/) { - push(@sections, $line); - } elsif ($line =~ /\.previous/) { - if (!$sections[-2]) { - die ".previous without a previous section"; - } - $line = $sections[-2]; - push(@sections, $line); - } - - $thumb = 1 if $line =~ /\.code\s+16|\.thumb/; - $thumb = 0 if $line =~ /\.code\s+32|\.arm/; - - # handle ldr , = - if ($line =~ /(.*)\s*ldr([\w\s\d]+)\s*,\s*=(.*)/ and $as_type ne "armasm") { - my $label = $literal_labels{$3}; - if (!$label) { - $label = "Literal_$literal_num"; - $literal_num++; - $literal_labels{$3} = $label; - } - $line = "$1 ldr$2, $label\n"; - } elsif ($line =~ /\.ltorg/ and $as_type ne "armasm") { - $line .= ".align 2\n"; - foreach my $literal (keys %literal_labels) { - $line .= "$literal_labels{$literal}:\n $literal_expr $literal\n"; - } - %literal_labels = (); - } - - # handle GNU as pc-relative relocations for adrp/add - if ($line =~ /(.*)\s*adrp([\w\s\d]+)\s*,\s*#?:pg_hi21:([^\s]+)/) { - $line = "$1 adrp$2, ${3}\@PAGE\n"; - } elsif ($line =~ /(.*)\s*add([\w\s\d]+)\s*,([\w\s\d]+)\s*,\s*#?:lo12:([^\s]+)/) { - $line = "$1 add$2, $3, ${4}\@PAGEOFF\n"; - } - - # thumb add with large immediate needs explicit add.w - if ($thumb and $line =~ /add\s+.*#([^@]+)/) { - $line =~ s/add/add.w/ if eval_expr($1) > 255; - } - - # mach-o local symbol names start with L (no dot) - $line =~ s/(? with ic as conditional code - if ($cond =~ /|$arm_cond_codes/) { - if (exists $thumb_labels{$label}) { - print ASMFILE ".thumb_func $label\n"; - } else { - $call_targets{$label}++; - } - } - } - - # @l -> lo16() @ha -> ha16() - $line =~ s/,\s+([^,]+)\@l\b/, lo16($1)/g; - $line =~ s/,\s+([^,]+)\@ha\b/, ha16($1)/g; - - # move to/from SPR - if ($line =~ /(\s+)(m[ft])([a-z]+)\s+(\w+)/ and exists $ppc_spr{$3}) { - if ($2 eq 'mt') { - $line = "$1${2}spr $ppc_spr{$3}, $4\n"; - } else { - $line = "$1${2}spr $4, $ppc_spr{$3}\n"; - } - } - - if ($line =~ /\.unreq\s+(.*)/) { - if (defined $neon_alias_reg{$1}) { - delete $neon_alias_reg{$1}; - delete $neon_alias_type{$1}; - return; - } elsif (defined $aarch64_req_alias{$1}) { - delete $aarch64_req_alias{$1}; - return; - } - } - # old gas versions store upper and lower case names on .req, - # but they remove only one on .unreq - if ($fix_unreq) { - if ($line =~ /\.unreq\s+(.*)/) { - $line = ".unreq " . lc($1) . "\n"; - $line .= ".unreq " . uc($1) . "\n"; - } - } - - if ($line =~ /(\w+)\s+\.(dn|qn)\s+(\w+)(?:\.(\w+))?(\[\d+\])?/) { - $neon_alias_reg{$1} = "$3$5"; - $neon_alias_type{$1} = $4; - return; - } - if (scalar keys %neon_alias_reg > 0 && $line =~ /^\s+v\w+/) { - # This line seems to possibly have a neon instruction - foreach (keys %neon_alias_reg) { - my $alias = $_; - # Require the register alias to match as an invididual word, not as a substring - # of a larger word-token. - if ($line =~ /\b$alias\b/) { - $line =~ s/\b$alias\b/$neon_alias_reg{$alias}/g; - # Add the type suffix. If multiple aliases match on the same line, - # only do this replacement the first time (a vfoo.bar string won't match v\w+). - $line =~ s/^(\s+)(v\w+)(\s+)/$1$2.$neon_alias_type{$alias}$3/; - } - } - } - - if ($arch eq "aarch64" or $as_type eq "armasm") { - # clang's integrated aarch64 assembler in Xcode 5 does not support .req/.unreq - if ($line =~ /\b(\w+)\s+\.req\s+(\w+)\b/) { - $aarch64_req_alias{$1} = $2; - return; - } - foreach (keys %aarch64_req_alias) { - my $alias = $_; - # recursively resolve aliases - my $resolved = $aarch64_req_alias{$alias}; - while (defined $aarch64_req_alias{$resolved}) { - $resolved = $aarch64_req_alias{$resolved}; - } - $line =~ s/\b$alias\b/$resolved/g; - } - } - if ($arch eq "aarch64") { - # fix missing aarch64 instructions in Xcode 5.1 (beta3) - # mov with vector arguments is not supported, use alias orr instead - if ($line =~ /^\s*mov\s+(v\d[\.{}\[\]\w]+),\s*(v\d[\.{}\[\]\w]+)\b\s*$/) { - $line = " orr $1, $2, $2\n"; - } - # movi 16, 32 bit shifted variant, shift is optional - if ($line =~ /^\s*movi\s+(v[0-3]?\d\.(?:2|4|8)[hsHS])\s*,\s*(#\w+)\b\s*$/) { - $line = " movi $1, $2, lsl #0\n"; - } - # Xcode 5 misses the alias uxtl. Replace it with the more general ushll. - # Clang 3.4 misses the alias sxtl too. Replace it with the more general sshll. - if ($line =~ /^\s*(s|u)xtl(2)?\s+(v[0-3]?\d\.[248][hsdHSD])\s*,\s*(v[0-3]?\d\.(?:2|4|8|16)[bhsBHS])\b\s*$/) { - $line = " $1shll$2 $3, $4, #0\n"; - } - # clang 3.4 does not automatically use shifted immediates in add/sub - if ($as_type eq "clang" and - $line =~ /^(\s*(?:add|sub)s?) ([^#l]+)#([\d\+\-\*\/ <>]+)\s*$/) { - my $imm = eval $3; - if ($imm > 4095 and not ($imm & 4095)) { - $line = "$1 $2#" . ($imm >> 12) . ", lsl #12\n"; - } - } - if ($ENV{GASPP_FIX_XCODE5}) { - if ($line =~ /^\s*bsl\b/) { - $line =~ s/\b(bsl)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; - $line =~ s/\b(v[0-3]?\d)\.$3\b/$1/g; - } - if ($line =~ /^\s*saddl2?\b/) { - $line =~ s/\b(saddl2?)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; - $line =~ s/\b(v[0-3]?\d)\.\w+\b/$1/g; - } - if ($line =~ /^\s*dup\b.*\]$/) { - $line =~ s/\bdup(\s+v[0-3]?\d)\.(\w+)\b/dup.$2$1/g; - $line =~ s/\b(v[0-3]?\d)\.[bhsdBHSD](\[\d\])$/$1$2/g; - } - } - } - - if ($as_type eq "armasm") { - # Also replace variables set by .set - foreach (keys %symbols) { - my $sym = $_; - $line =~ s/\b$sym\b/$symbols{$sym}/g; - } - - # Handle function declarations and keep track of the declared labels - if ($line =~ s/^\s*\.func\s+(\w+)/$1 PROC/) { - $labels_seen{$1} = 1; - } - - if ($line =~ s/^(\d+)://) { - # Convert local labels into unique labels. armasm (at least in - # RVCT) has something similar, but still different enough. - # By converting to unique labels we avoid any possible - # incompatibilities. - - my $num = $1; - foreach (@{$next_temp_labels{$num}}) { - $line = "$_\n" . $line; - } - @next_temp_labels{$num} = (); - my $name = "temp_label_$temp_label_next"; - $temp_label_next++; - # The matching regexp above removes the label from the start of - # the line (which might contain an instruction as well), readd - # it on a separate line above it. - $line = "$name:\n" . $line; - $last_temp_labels{$num} = $name; - } - - if ($line =~ s/^(\w+):/$1/) { - # Skip labels that have already been declared with a PROC, - # labels must not be declared multiple times. - return if (defined $labels_seen{$1}); - $labels_seen{$1} = 1; - } elsif ($line !~ /(\w+) PROC/) { - # If not a label, make sure the line starts with whitespace, - # otherwise ms armasm interprets it incorrectly. - $line =~ s/^[\.\w]/\t$&/; - } - - - # Check branch instructions - if ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(bl?x?(..)?(\.w)?)\s+(\w+)/) { - my $instr = $2; - my $cond = $3; - my $width = $4; - my $target = $5; - # Don't interpret e.g. bic as b with ic as conditional code - if ($cond !~ /|$arm_cond_codes/) { - # Not actually a branch - } elsif ($target =~ /(\d+)([bf])/) { - # The target is a local label - $line = handle_local_label($line, $1, $2); - $line =~ s/\b$instr\b/$&.w/ if $width eq ""; - } elsif (!is_arm_register($target)) { - $call_targets{$target}++; - } - } elsif ($line =~ /^\s*.h?word.*\b\d+[bf]\b/) { - while ($line =~ /\b(\d+)([bf])\b/g) { - $line = handle_local_label($line, $1, $2); - } - } - - # ALIGN in armasm syntax is the actual number of bytes - if ($line =~ /\.align\s+(\d+)/) { - my $align = 1 << $1; - $line =~ s/\.align\s(\d+)/ALIGN $align/; - } - # Convert gas style [r0, :128] into armasm [r0@128] alignment specification - $line =~ s/\[([^\[]+),\s*:(\d+)\]/[$1\@$2]/g; - - # armasm treats logical values {TRUE} and {FALSE} separately from - # numeric values - logical operators and values can't be intermixed - # with numerical values. Evaluate ! and (a <> b) into numbers, - # let the assembler evaluate the rest of the expressions. This current - # only works for cases when ! and <> are used with actual constant numbers, - # we don't evaluate subexpressions here. - - # Evaluate ! - while ($line =~ /!\s*(\d+)/g) { - my $val = ($1 != 0) ? 0 : 1; - $line =~ s/!(\d+)/$val/; - } - # Evaluate (a > b) - while ($line =~ /\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/) { - my $val; - if ($2 eq "<") { - $val = ($1 < $3) ? 1 : 0; - } else { - $val = ($1 > $3) ? 1 : 0; - } - $line =~ s/\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/$val/; - } - - # Change a movw... #:lower16: into a mov32 pseudoinstruction - $line =~ s/^(\s*)movw(\s+\w+\s*,\s*)\#:lower16:(.*)$/$1mov32$2$3/; - # and remove the following, matching movt completely - $line =~ s/^\s*movt\s+\w+\s*,\s*\#:upper16:.*$//; - - if ($line =~ /^\s*mov32\s+\w+,\s*([a-zA-Z]\w*)/) { - $mov32_targets{$1}++; - } - - # Misc bugs/deficiencies: - # armasm seems unable to parse e.g. "vmov s0, s1" without a type - # qualifier, thus add .f32. - $line =~ s/^(\s+(?:vmov|vadd))(\s+s)/$1.f32$2/; - # armasm is unable to parse &0x - add spacing - $line =~ s/&0x/& 0x/g; - } - - if ($force_thumb) { - # Convert register post indexing to a separate add instruction. - # This converts e.g. "ldr r0, [r1], r2" into "ldr r0, [r1]", - # "add r1, r1, r2". - $line =~ s/(ldr|str)\s+(\w+),\s*\[(\w+)\],\s*(\w+)/$1 $2, [$3]\n\tadd $3, $3, $4/g; - - # Convert "mov pc, lr" into "bx lr", since the former only works - # for switching from arm to thumb (and only in armv7), but not - # from thumb to arm. - s/mov\s*pc\s*,\s*lr/bx lr/g; - - # Convert stmdb/ldmia with only one register into a plain str/ldr with post-increment/decrement - $line =~ s/stmdb\s+sp!\s*,\s*\{([^,-]+)\}/str $1, [sp, #-4]!/g; - $line =~ s/ldmia\s+sp!\s*,\s*\{([^,-]+)\}/ldr $1, [sp], #4/g; - - $line =~ s/\.arm/.thumb/x; - } - - # comment out unsupported directives - $line =~ s/\.type/$comm$&/x if $as_type =~ /^(apple-|armasm)/; - $line =~ s/\.func/$comm$&/x if $as_type =~ /^(apple-|clang)/; - $line =~ s/\.endfunc/$comm$&/x if $as_type =~ /^(apple-|clang)/; - $line =~ s/\.endfunc/ENDP/x if $as_type =~ /armasm/; - $line =~ s/\.ltorg/$comm$&/x if $as_type =~ /^(apple-|clang)/; - $line =~ s/\.ltorg/LTORG/x if $as_type eq "armasm"; - $line =~ s/\.size/$comm$&/x if $as_type =~ /^(apple-|armasm)/; - $line =~ s/\.fpu/$comm$&/x if $as_type =~ /^(apple-|armasm)/; - $line =~ s/\.arch/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; - $line =~ s/\.object_arch/$comm$&/x if $as_type =~ /^(apple-|armasm)/; - $line =~ s/.section\s+.note.GNU-stack.*/$comm$&/x if $as_type =~ /^(apple-|armasm)/; - $line =~ s/\.hidden/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; - - $line =~ s/\.syntax/$comm$&/x if $as_type =~ /armasm/; - - $line =~ s/\.hword/.short/x; - - if ($as_type =~ /^apple-/) { - # the syntax for these is a little different - $line =~ s/\.global/.globl/x; - # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const - $line =~ s/(.*)\.rodata/.const_data/x; - $line =~ s/\.int/.long/x; - $line =~ s/\.float/.single/x; - } - if ($as_type eq "armasm") { - $line =~ s/\.global/EXPORT/x; - $line =~ s/\.int/dcd/x; - $line =~ s/\.long/dcd/x; - $line =~ s/\.float/dcfs/x; - $line =~ s/\.word/dcd/x; - $line =~ s/\.short/dcw/x; - $line =~ s/\.byte/dcb/x; - $line =~ s/\.thumb/THUMB/x; - $line =~ s/\.arm/ARM/x; - # The alignment in AREA is the power of two, just as .align in gas - $line =~ s/\.text/AREA |.text|, CODE, READONLY, ALIGN=2, CODEALIGN/; - $line =~ s/(\s*)(.*)\.rodata/$1AREA |.rodata|, DATA, READONLY, ALIGN=5/; - - $line =~ s/fmxr/vmsr/; - $line =~ s/fmrx/vmrs/; - $line =~ s/fadds/vadd/; - } - - # catch unknown section names that aren't mach-o style (with a comma) - if ($as_type =~ /apple-/ and $line =~ /.section ([^,]*)$/) { - die ".section $1 unsupported; figure out the mach-o section name and add it"; - } - - print ASMFILE $line; -} - -if ($as_type ne "armasm") { - print ASMFILE ".text\n"; - print ASMFILE ".align 2\n"; - foreach my $literal (keys %literal_labels) { - print ASMFILE "$literal_labels{$literal}:\n $literal_expr $literal\n"; - } - - map print(ASMFILE ".thumb_func $_\n"), - grep exists $thumb_labels{$_}, keys %call_targets; -} else { - map print(ASMFILE "\tIMPORT $_\n"), - grep ! exists $labels_seen{$_}, (keys %call_targets, keys %mov32_targets); - - print ASMFILE "\tEND\n"; -} - -close(INPUT) or exit 1; -close(ASMFILE) or exit 1; -if ($as_type eq "armasm" and ! defined $ENV{GASPP_DEBUG}) { - system(@gcc_cmd) == 0 or die "Error running assembler"; -} - -END { - unlink($tempfile) if defined $tempfile; -} -#exit 1 -- cgit v1.3.1