Ver Fonte

ASM_MARMASM: Add support for Microsoft ARM assembler language

https://learn.microsoft.com/en-us/cpp/assembler/arm/arm-assembler-reference

Fixes: #23999
Ilia K há 3 anos atrás
pai
commit
3166547cf6

+ 8 - 2
Help/envvar/ASM_DIALECT.rst

@@ -4,8 +4,14 @@ ASM<DIALECT>
 .. include:: ENV_VAR.txt
 
 Preferred executable for compiling a specific dialect of assembly language
-files. ``ASM<DIALECT>`` can be ``ASM``, ``ASM_NASM`` (Netwide Assembler),
-``ASM_MASM`` (Microsoft Assembler) or ``ASM-ATT`` (Assembler AT&T).
+files. ``ASM<DIALECT>`` can be one of:
+
+* ``ASM``
+* ``ASM_NASM`` (Netwide Assembler)
+* ``ASM_MASM`` (Microsoft Assembler)
+* ``ASM_MARMASM`` (Microsoft ARM Assembler)
+* ``ASM-ATT`` (Assembler AT&T)
+
 Will only be used by CMake on the first configuration to determine
 ``ASM<DIALECT>`` compiler, after which the value for ``ASM<DIALECT>`` is stored
 in the cache as

+ 1 - 0
Help/envvar/ASM_DIALECTFLAGS.rst

@@ -9,6 +9,7 @@ of an assembly language.  ``ASM<DIALECT>FLAGS`` can be one of:
 * ``ASMFLAGS``
 * ``ASM_NASMFLAGS``
 * ``ASM_MASMFLAGS``
+* ``ASM_MARMASMFLAGS``
 * ``ASM-ATTFLAGS``
 
 .. |CMAKE_LANG_FLAGS| replace:: :variable:`CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>`

+ 4 - 0
Help/release/dev/marmasm-language.rst

@@ -0,0 +1,4 @@
+marmasm-language
+----------------
+
+* The ``ASM_MARMASM`` language was added to support the Microsoft ARM assembler language.

+ 20 - 0
Modules/CMakeASM_MARMASMInformation.cmake

@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# support for the MS ARM assembler, marmasm and marmasm64
+
+set(ASM_DIALECT "_MARMASM")
+
+set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS asm)
+
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
+
+# The ASM_MARMASM compiler id for this compiler is "MSVC", so fill out the runtime library table.
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
+
+include(CMakeASMInformation)
+set(ASM_DIALECT)

+ 18 - 0
Modules/CMakeDetermineASM_MARMASMCompiler.cmake

@@ -0,0 +1,18 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# Find the MS ARM assembler (marmasm or marmasm64)
+
+set(ASM_DIALECT "_MARMASM")
+
+# if we are using the 64bit cl compiler, assume we also want the 64bit assembler
+if(";${CMAKE_VS_PLATFORM_NAME};${CMAKE_C_COMPILER_ARCHITECTURE_ID};${CMAKE_CXX_COMPILER_ARCHITECTURE_ID};"
+    MATCHES ";(ARM64);")
+  set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT armasm64)
+else()
+  set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT armasm)
+endif()
+
+include(CMakeDetermineASMCompiler)
+set(ASM_DIALECT)

+ 13 - 0
Modules/CMakeTestASM_MARMASMCompiler.cmake

@@ -0,0 +1,13 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected ASM_MARMASM "compiler" (should be marmasm or marmasm64)
+# works. For assembler this can only check whether the compiler has been found,
+# because otherwise there would have to be a separate assembler source file
+# for each assembler on every architecture.
+
+set(ASM_DIALECT "_MARMASM")
+include(CMakeTestASMCompiler)
+set(ASM_DIALECT)

+ 2 - 1
Source/cmGlobalGenerator.cxx

@@ -827,7 +827,8 @@ void cmGlobalGenerator::EnableLanguage(
         "No " << compilerName << " could be found.\n"
         ;
       /* clang-format on */
-    } else if ((lang != "RC") && (lang != "ASM_MASM")) {
+    } else if ((lang != "RC") && (lang != "ASM_MARMASM") &&
+               (lang != "ASM_MASM")) {
       if (!cmSystemTools::FileIsFullPath(*compilerFile)) {
         /* clang-format off */
         noCompiler <<

+ 8 - 0
Source/cmGlobalVisualStudio10Generator.cxx

@@ -56,6 +56,7 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
 {
   this->DefaultCudaFlagTableName = "v10";
   this->DefaultCudaHostFlagTableName = "v10";
+  this->DefaultMarmasmFlagTableName = "v10";
   this->DefaultNasmFlagTableName = "v10";
 }
 
@@ -1466,6 +1467,13 @@ cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable()
                        "CudaHost");
 }
 
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMarmasmFlagTable()
+  const
+{
+  return LoadFlagTable(std::string(), this->DefaultMarmasmFlagTableName,
+                       "MARMASM");
+}
+
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
 {
   return LoadFlagTable(this->GetMasmFlagTableName(),

+ 2 - 0
Source/cmGlobalVisualStudio10Generator.h

@@ -163,6 +163,7 @@ public:
   cmIDEFlagTable const* GetLinkFlagTable() const;
   cmIDEFlagTable const* GetCudaFlagTable() const;
   cmIDEFlagTable const* GetCudaHostFlagTable() const;
+  cmIDEFlagTable const* GetMarmasmFlagTable() const;
   cmIDEFlagTable const* GetMasmFlagTable() const;
   cmIDEFlagTable const* GetNasmFlagTable() const;
 
@@ -226,6 +227,7 @@ protected:
   std::string DefaultLinkFlagTableName;
   std::string DefaultCudaFlagTableName;
   std::string DefaultCudaHostFlagTableName;
+  std::string DefaultMarmasmFlagTableName;
   std::string DefaultMasmFlagTableName;
   std::string DefaultNasmFlagTableName;
   std::string DefaultRCFlagTableName;

+ 12 - 0
Source/cmGlobalVisualStudio11Generator.cxx

@@ -161,6 +161,18 @@ bool cmGlobalVisualStudio11Generator::MatchesGeneratorName(
   return false;
 }
 
+void cmGlobalVisualStudio11Generator::EnableLanguage(
+  std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+  for (std::string const& it : lang) {
+    if (it == "ASM_MARMASM") {
+      this->MarmasmEnabled = true;
+    }
+  }
+  this->AddPlatformDefinitions(mf);
+  cmGlobalVisualStudio10Generator::EnableLanguage(lang, mf, optional);
+}
+
 bool cmGlobalVisualStudio11Generator::InitializeWindowsPhone(cmMakefile* mf)
 {
   if (!this->SelectWindowsPhoneToolset(this->DefaultPlatformToolset)) {

+ 3 - 0
Source/cmGlobalVisualStudio11Generator.h

@@ -25,6 +25,9 @@ public:
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
+  void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+                      bool optional) override;
+
   bool SupportsCustomCommandDepfile() const override { return true; }
 
   cm::optional<cmDepfileFormat> DepfileFormat() const override

+ 1 - 0
Source/cmGlobalVisualStudio7Generator.cxx

@@ -70,6 +70,7 @@ cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(
   : cmGlobalVisualStudioGenerator(cm, platformInGeneratorName)
 {
   this->DevEnvCommandInitialized = false;
+  this->MarmasmEnabled = false;
   this->MasmEnabled = false;
   this->NasmEnabled = false;
   this->ExtraFlagTable = cmVS7ExtraFlagTable;

+ 2 - 0
Source/cmGlobalVisualStudio7Generator.h

@@ -106,6 +106,7 @@ public:
   bool FindMakeProgram(cmMakefile* mf) override;
 
   /** Is the Microsoft Assembler enabled?  */
+  bool IsMarmasmEnabled() const { return this->MarmasmEnabled; }
   bool IsMasmEnabled() const { return this->MasmEnabled; }
   bool IsNasmEnabled() const { return this->NasmEnabled; }
 
@@ -176,6 +177,7 @@ protected:
   // Set during OutputSLNFile with the name of the current project.
   // There is one SLN file per project.
   std::string CurrentProject;
+  bool MarmasmEnabled;
   bool MasmEnabled;
   bool NasmEnabled;
 

+ 33 - 0
Source/cmLocalVisualStudio7Generator.cxx

@@ -842,6 +842,24 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
     }
   }
   fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool
+  if (gg->IsMarmasmEnabled() && !this->FortranProject) {
+    Options marmasmOptions(this, Options::MarmasmCompiler, 0, 0);
+    /* clang-format off */
+    fout <<
+      "\t\t\t<Tool\n"
+      "\t\t\t\tName=\"MARMASM\"\n"
+      ;
+    /* clang-format on */
+    targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "ASM_MARMASM");
+    // Use same preprocessor definitions as VCCLCompilerTool.
+    targetOptions.OutputPreprocessorDefinitions(fout, 4, "ASM_MARMASM");
+    marmasmOptions.OutputFlagMap(fout, 4);
+    /* clang-format off */
+    fout <<
+      "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"
+      "\t\t\t/>\n";
+    /* clang-format on */
+  }
   if (gg->IsMasmEnabled() && !this->FortranProject) {
     Options masmOptions(this, Options::MasmCompiler, 0, 0);
     /* clang-format off */
@@ -1720,6 +1738,10 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
             aCompilerTool = "VFCustomBuildTool";
           }
         }
+        if (gg->IsMarmasmEnabled() && !this->FortranProject &&
+            lang == "ASM_MARMASM") {
+          aCompilerTool = "MARMASM";
+        }
         if (gg->IsMasmEnabled() && !this->FortranProject &&
             lang == "ASM_MASM") {
           aCompilerTool = "MASM";
@@ -2050,6 +2072,17 @@ void cmLocalVisualStudio7Generator::WriteProjectStart(
        << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
        << "\t</Platforms>\n";
   /* clang-format on */
+  if (gg->IsMarmasmEnabled()) {
+    /* clang-format off */
+    fout <<
+      "\t<ToolFiles>\n"
+      "\t\t<DefaultToolFile\n"
+      "\t\t\tFileName=\"marmasm.rules\"\n"
+      "\t\t/>\n"
+      "\t</ToolFiles>\n"
+      ;
+    /* clang-format on */
+  }
   if (gg->IsMasmEnabled()) {
     /* clang-format off */
     fout <<

+ 73 - 0
Source/cmVisualStudio10TargetGenerator.cxx

@@ -406,6 +406,9 @@ void cmVisualStudio10TargetGenerator::Generate()
     if (!this->ComputeCudaLinkOptions()) {
       return;
     }
+    if (!this->ComputeMarmasmOptions()) {
+      return;
+    }
     if (!this->ComputeMasmOptions()) {
       return;
     }
@@ -732,6 +735,11 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
                        this->GlobalGenerator->GetPlatformToolsetCuda() +
                        ".props");
       }
+      if (this->GlobalGenerator->IsMarmasmEnabled()) {
+        Elem(e1, "Import")
+          .Attribute("Project",
+                     "$(VCTargetsPath)\\BuildCustomizations\\marmasm.props");
+      }
       if (this->GlobalGenerator->IsMasmEnabled()) {
         Elem(e1, "Import")
           .Attribute("Project",
@@ -830,6 +838,11 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
                        this->GlobalGenerator->GetPlatformToolsetCuda() +
                        ".targets");
       }
+      if (this->GlobalGenerator->IsMarmasmEnabled()) {
+        Elem(e1, "Import")
+          .Attribute("Project",
+                     "$(VCTargetsPath)\\BuildCustomizations\\marmasm.targets");
+      }
       if (this->GlobalGenerator->IsMasmEnabled()) {
         Elem(e1, "Import")
           .Attribute("Project",
@@ -2485,6 +2498,9 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
         const std::string& lang = si.Source->GetLanguage();
         if (lang == "C" || lang == "CXX") {
           tool = "ClCompile";
+        } else if (lang == "ASM_MARMASM" &&
+                   this->GlobalGenerator->IsMarmasmEnabled()) {
+          tool = "MARMASM";
         } else if (lang == "ASM_MASM" &&
                    this->GlobalGenerator->IsMasmEnabled()) {
           tool = "MASM";
@@ -2740,6 +2756,9 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
       const std::string& srclang = source->GetLanguage();
       if (srclang == "C" || srclang == "CXX") {
         flagtable = gg->GetClFlagTable();
+      } else if (srclang == "ASM_MARMASM" &&
+                 this->GlobalGenerator->IsMarmasmEnabled()) {
+        flagtable = gg->GetMarmasmFlagTable();
       } else if (srclang == "ASM_MASM" &&
                  this->GlobalGenerator->IsMasmEnabled()) {
         flagtable = gg->GetMasmFlagTable();
@@ -3751,6 +3770,59 @@ void cmVisualStudio10TargetGenerator::WriteCudaLinkOptions(
   cudaLinkOptions.OutputFlagMap();
 }
 
+bool cmVisualStudio10TargetGenerator::ComputeMarmasmOptions()
+{
+  if (!this->GlobalGenerator->IsMarmasmEnabled()) {
+    return true;
+  }
+  for (std::string const& c : this->Configurations) {
+    if (!this->ComputeMarmasmOptions(c)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeMarmasmOptions(
+  std::string const& configName)
+{
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+  auto pOptions = cm::make_unique<Options>(
+    this->LocalGenerator, Options::MarmasmCompiler, gg->GetMarmasmFlagTable());
+  Options& marmasmOptions = *pOptions;
+
+  std::string flags;
+  this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+                                         cmBuildStep::Compile, "ASM_MARMASM",
+                                         configName);
+
+  marmasmOptions.Parse(flags);
+
+  // Get includes for this target
+  marmasmOptions.AddIncludes(this->GetIncludes(configName, "ASM_MARMASM"));
+
+  this->MarmasmOptions[configName] = std::move(pOptions);
+  return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteMarmasmOptions(
+  Elem& e1, std::string const& configName)
+{
+  if (!this->MSTools || !this->GlobalGenerator->IsMarmasmEnabled()) {
+    return;
+  }
+  Elem e2(e1, "MARMASM");
+
+  // Preprocessor definitions and includes are shared with clOptions.
+  OptionsHelper clOptions(*(this->ClOptions[configName]), e2);
+  clOptions.OutputPreprocessorDefinitions("ASM_MARMASM");
+
+  OptionsHelper marmasmOptions(*(this->MarmasmOptions[configName]), e2);
+  marmasmOptions.OutputAdditionalIncludeDirectories("ASM_MARMASM");
+  marmasmOptions.PrependInheritedString("AdditionalOptions");
+  marmasmOptions.OutputFlagMap();
+}
+
 bool cmVisualStudio10TargetGenerator::ComputeMasmOptions()
 {
   if (!this->GlobalGenerator->IsMasmEnabled()) {
@@ -4451,6 +4523,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups(Elem& e0)
       //    output rc compile flags <ResourceCompile></ResourceCompile>
       this->WriteRCOptions(e1, c);
       this->WriteCudaOptions(e1, c);
+      this->WriteMarmasmOptions(e1, c);
       this->WriteMasmOptions(e1, c);
       this->WriteNasmOptions(e1, c);
     }

+ 4 - 0
Source/cmVisualStudio10TargetGenerator.h

@@ -132,6 +132,9 @@ private:
   bool ComputeCudaLinkOptions(std::string const& config);
   void WriteCudaLinkOptions(Elem& e1, std::string const& config);
 
+  bool ComputeMarmasmOptions();
+  bool ComputeMarmasmOptions(std::string const& config);
+  void WriteMarmasmOptions(Elem& e1, std::string const& config);
   bool ComputeMasmOptions();
   bool ComputeMasmOptions(std::string const& config);
   void WriteMasmOptions(Elem& e1, std::string const& config);
@@ -208,6 +211,7 @@ private:
   OptionsMap RcOptions;
   OptionsMap CudaOptions;
   OptionsMap CudaLinkOptions;
+  OptionsMap MarmasmOptions;
   OptionsMap MasmOptions;
   OptionsMap NasmOptions;
   OptionsMap LinkOptions;

+ 1 - 0
Source/cmVisualStudioGeneratorOptions.h

@@ -24,6 +24,7 @@ public:
     Compiler,
     ResourceCompiler,
     CudaCompiler,
+    MarmasmCompiler,
     MasmCompiler,
     NasmCompiler,
     Linker,

+ 149 - 0
Templates/MSBuild/FlagTables/v10_MARMASM.json

@@ -0,0 +1,149 @@
+[
+  {
+    "name": "16BitThumbInstructions",
+    "switch": "16",
+    "comment": "Assemble source as 16-bit Thumb instructions.",
+    "value": "true",
+    "flags": []
+  },
+  {
+    "name": "32BitArmInstructions",
+    "switch": "32",
+    "comment": "Assemble source as 32-bit ARM instructions.",
+    "value": "true",
+    "flags": []
+  },
+  {
+    "name": "CoffThumb2Only",
+    "switch": "coff_thumb2_only",
+    "comment": "Allow only Thumb-2 code.",
+    "value": "true",
+    "flags": []
+  },
+  {
+    "name": "ErrorReporting",
+    "switch": "errorReport:prompt",
+    "comment": "Prompt to send report immediately (/errorReport:prompt)",
+    "value": "0",
+    "flags": []
+  },
+  {
+    "name": "ErrorReporting",
+    "switch": "errorReport:queue",
+    "comment": "Prompt to send report at the next logon (/errorReport:queue)",
+    "value": "1",
+    "flags": []
+  },
+  {
+    "name": "ErrorReporting",
+    "switch": "errorReport:send",
+    "comment": "Automatically send report (/errorReport:send)",
+    "value": "2",
+    "flags": []
+  },
+  {
+    "name": "ErrorReporting",
+    "switch": "errorReport:none",
+    "comment": "Do not send report (/errorReport:none)",
+    "value": "3",
+    "flags": []
+  },
+  {
+    "name": "Errors",
+    "switch": "errors",
+    "comment": "Redirect error and warning messages.",
+    "value": "",
+    "flags": [
+      "UserValue"
+    ]
+  },
+  {
+    "name": "FunctionOverride",
+    "switch": "funcOverride",
+    "comment": "Emit function overriding support for the specified function.",
+    "value": "",
+    "flags": [
+      "UserValue"
+    ]
+  },
+  {
+    "name": "DebugInformation",
+    "switch": "g",
+    "comment": "Generate debugging information.",
+    "value": "true",
+    "flags": []
+  },
+  {
+    "name": "Machine",
+    "switch": "machine",
+    "comment": "Specify the machine type to set in the PE header.",
+    "value": "",
+    "flags": [
+      "UserValue"
+    ]
+  },
+  {
+    "name": "NoEsc",
+    "switch": "noesc",
+    "comment": "Ignore C-style escaped special characters.",
+    "value": "true",
+    "flags": []
+  },
+  {
+    "name": "NoLogo",
+    "switch": "nologo",
+    "comment": "Suppress the copyright banner.",
+    "value": "true",
+    "flags": []
+  },
+  {
+    "name": "NoWarn",
+    "switch": "nowarn",
+    "comment": "Disable all warning messages.",
+    "value": "true",
+    "flags": []
+  },
+  {
+    "name": "ObjectFile",
+    "switch": "o",
+    "comment": "Specify the name of the object (output) file.",
+    "value": "",
+    "flags": [
+      "UserValue"
+    ]
+  },
+  {
+    "name": "ItBlocks",
+    "switch": "oldit",
+    "comment": "Generate ARMv7-style IT blocks.",
+    "value": "true",
+    "flags": []
+  },
+  {
+    "name": "PredefineDirective",
+    "switch": "predefine",
+    "comment": "Specify a SETA, SETL, or SETS directive to predefine a symbol.",
+    "value": "",
+    "flags": [
+      "UserValue"
+    ]
+  },
+  {
+    "name": "SourceLink",
+    "switch": "sourcelink",
+    "comment": "Specify the configuration file that contains a simple mapping of local file paths to URLs for source files to display in the debugger.",
+    "value": "",
+    "flags": [
+      "UserValue"
+    ]
+  },
+  {
+    "name": "CommandLineArgumentsViaFile",
+    "switch": "via",
+    "comment": "Read extra command-line arguments from the specified file.",
+    "value": "",
+    "flags": [
+      "UserValue"
+    ]
+  }
+]

+ 6 - 0
Tests/CMakeLists.txt

@@ -2161,6 +2161,12 @@ if(BUILD_TESTING)
     list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/MFC")
   endif()
 
+  if(MSVC AND NOT MSVC_VERSION LESS 1700
+     AND (CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64")
+      )
+    ADD_TEST_MACRO(VSMARMASM VSMARMASM)
+  endif()
+
   if(MSVC AND NOT MSVC_VERSION LESS 1310
      AND (NOT CMAKE_GENERATOR MATCHES "Visual Studio 9 "
           OR CMAKE_SIZEOF_VOID_P EQUAL 4)

+ 3 - 0
Tests/VSMARMASM/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(VSMARMASM C ASM_MARMASM)
+add_executable(VSMARMASM main.c foo.asm)

+ 10 - 0
Tests/VSMARMASM/foo.asm

@@ -0,0 +1,10 @@
+    AREA |.text|, CODE
+
+    EXPORT foo
+
+foo PROC
+    mov w0, #0
+    ret
+    ENDP
+
+    END

+ 5 - 0
Tests/VSMARMASM/main.c

@@ -0,0 +1,5 @@
+extern int foo(void);
+int main(void)
+{
+  return foo();
+}