diff --git a/README.md b/README.md index ef5c742b33..922a17db4e 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ end with a fully operational Zig compiler for any target. This repository copies sources from upstream. Patches listed below. Use git to find and inspect the patch diffs. - * LLVM, LLD, Clang release/13.x (13.0.1-rc1+d4a57c84) + * LLVM, LLD, Clang 13.0.1 * zlib 1.2.11 - * Zig 0.9.0 + * Zig 0.9.1 For other versions, check the git tags of this repository. diff --git a/build b/build index 9eb463fe7e..08805981d7 100755 --- a/build +++ b/build @@ -7,7 +7,7 @@ TARGET="$2" # Example: riscv64-linux-gnu MCPU="$3" # Examples: `baseline`, `native`, `generic+v7a`, or `arm1176jzf_s` ROOTDIR="$(pwd)" -ZIG_VERSION="0.9.0" +ZIG_VERSION="0.9.1" TARGET_OS_AND_ABI=${TARGET#*-} # Example: linux-gnu diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 0805642824..87c2f6f9f0 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -3361,7 +3361,7 @@ CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) { // Save "Succ" in BackpatchBlocks. In the backpatch processing, "Succ" is // used to avoid adding "Succ" again. BackpatchBlocks.push_back(JumpSource(Succ, ScopePos)); - return Block; + return VisitChildren(G); } CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp index a38ae34f4b..811146e50b 100644 --- a/clang/lib/Analysis/UninitializedValues.cpp +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -819,12 +819,11 @@ void TransferFunctions::VisitGCCAsmStmt(GCCAsmStmt *as) { while (const auto *UO = dyn_cast(Ex)) Ex = stripCasts(C, UO->getSubExpr()); + // Mark the variable as potentially uninitialized for those cases where + // it's used on an indirect path, where it's not guaranteed to be + // defined. if (const VarDecl *VD = findVar(Ex).getDecl()) - if (vals[VD] != Initialized) - // If the variable isn't initialized by the time we get here, then we - // mark it as potentially uninitialized for those cases where it's used - // on an indirect path, where it's not guaranteed to be defined. - vals[VD] = MayUninitialized; + vals[VD] = MayUninitialized; } } diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 59656888e2..ecfbe284fb 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -243,7 +243,10 @@ static void defineXLCompatMacros(MacroBuilder &Builder) { void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - defineXLCompatMacros(Builder); + // We define the XLC compatibility macros only on AIX and Linux since XLC + // was never available on any other platforms. + if (getTriple().isOSAIX() || getTriple().isOSLinux()) + defineXLCompatMacros(Builder); // Target identification. Builder.defineMacro("__ppc__"); diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h index 07844abafe..e9f8c10db7 100644 --- a/clang/lib/Basic/Targets/Sparc.h +++ b/clang/lib/Basic/Targets/Sparc.h @@ -50,8 +50,6 @@ class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo { bool hasFeature(StringRef Feature) const override; - bool hasSjLjLowering() const override { return true; } - ArrayRef getTargetBuiltins() const override { // FIXME: Implement! return None; @@ -180,7 +178,6 @@ class LLVM_LIBRARY_VISIBILITY SparcV8TargetInfo : public SparcTargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - bool hasSjLjLowering() const override { return true; } bool hasExtIntType() const override { return true; } }; diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index ed8c7e94b0..0e354a49b5 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -191,7 +191,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, bool success = true; // Enable NEON by default. Features.push_back("+neon"); - llvm::StringRef WaMArch = ""; + llvm::StringRef WaMArch; if (ForAS) for (const auto *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) @@ -201,7 +201,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, // Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or // "-Xassembler -march" is detected. Otherwise it may return false // and causes Clang to error out. - if (WaMArch.size()) + if (!WaMArch.empty()) success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Features); else if ((A = Args.getLastArg(options::OPT_march_EQ))) success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features); @@ -222,8 +222,15 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, success = getAArch64MicroArchFeaturesFromMcpu( D, getAArch64TargetCPU(Args, Triple, A), Args, Features); - if (!success) - D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); + if (!success) { + auto Diag = D.Diag(diag::err_drv_clang_unsupported); + // If "-Wa,-march=" is used, 'WaMArch' will contain the argument's value, + // while 'A' is uninitialized. Only dereference 'A' in the other case. + if (!WaMArch.empty()) + Diag << "-march=" + WaMArch.str(); + else + Diag << A->getAsString(Args); + } if (Args.getLastArg(options::OPT_mgeneral_regs_only)) { Features.push_back("-fp-armv8"); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f04eb91990..4179249e91 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15868,7 +15868,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // promoted type and the underlying type are the same except for // signedness. Ask the AST for the correctly corresponding type and see // if that's compatible. - if (!PromoteType.isNull() && + if (!PromoteType.isNull() && !UnderlyingType->isBooleanType() && PromoteType->isUnsignedIntegerType() != UnderlyingType->isUnsignedIntegerType()) { UnderlyingType = diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt index 4c54644c5e..f98acda2be 100644 --- a/lld/CMakeLists.txt +++ b/lld/CMakeLists.txt @@ -204,7 +204,6 @@ if (LLVM_INCLUDE_TESTS) add_subdirectory(unittests) endif() -add_subdirectory(docs) add_subdirectory(COFF) add_subdirectory(ELF) add_subdirectory(MachO) diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp index aaecef6ee9..d9334d5bf8 100644 --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -20,6 +20,9 @@ using namespace llvm::ELF; using namespace lld; using namespace lld::elf; +// Undefine the macro predefined by GCC powerpc32. +#undef PPC + namespace { class PPC final : public TargetInfo { public: diff --git a/lld/docs/AtomLLD.rst b/lld/docs/AtomLLD.rst deleted file mode 100644 index 2766094696..0000000000 --- a/lld/docs/AtomLLD.rst +++ /dev/null @@ -1,62 +0,0 @@ -ATOM-based lld -============== - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -ATOM-based lld is a new set of modular code for creating linker tools. -Currently it supports Mach-O. - -* End-User Features: - - * Compatible with existing linker options - * Reads standard Object Files - * Writes standard Executable Files - * Remove clang's reliance on "the system linker" - * Uses the LLVM `"UIUC" BSD-Style license`__. - -* Applications: - - * Modular design - * Support cross linking - * Easy to add new CPU support - * Can be built as static tool or library - -* Design and Implementation: - - * Extensive unit tests - * Internal linker model can be dumped/read to textual format - * Additional linking features can be plugged in as "passes" - * OS specific and CPU specific code factored out - -Why a new linker? ------------------ - -The fact that clang relies on whatever linker tool you happen to have installed -means that clang has been very conservative adopting features which require a -recent linker. - -In the same way that the MC layer of LLVM has removed clang's reliance on the -system assembler tool, the lld project will remove clang's reliance on the -system linker tool. - - -Contents --------- - -.. toctree:: - :maxdepth: 2 - - design - getting_started - development - open_projects - sphinx_intro - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`search` - -__ https://llvm.org/docs/DeveloperPolicy.html#license diff --git a/lld/docs/CMakeLists.txt b/lld/docs/CMakeLists.txt deleted file mode 100644 index 112ce35e8c..0000000000 --- a/lld/docs/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -if (LLVM_ENABLE_SPHINX) - include(AddSphinxTarget) - if (SPHINX_FOUND) - if (${SPHINX_OUTPUT_HTML}) - add_sphinx_target(html lld) - endif() - endif() -endif() diff --git a/lld/docs/Driver.rst b/lld/docs/Driver.rst deleted file mode 100644 index 0ac86ff65f..0000000000 --- a/lld/docs/Driver.rst +++ /dev/null @@ -1,82 +0,0 @@ -====== -Driver -====== - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -.. contents:: - :local: - -Introduction -============ - -This document describes the lld driver. The purpose of this document is to -describe both the motivation and design goals for the driver, as well as details -of the internal implementation. - -Overview -======== - -The lld driver is designed to support a number of different command line -interfaces. The main interfaces we plan to support are binutils' ld, Apple's -ld, and Microsoft's link.exe. - -Flavors -------- - -Each of these different interfaces is referred to as a flavor. There is also an -extra flavor "core" which is used to exercise the core functionality of the -linker it the test suite. - -* gnu -* darwin -* link -* core - -Selecting a Flavor -^^^^^^^^^^^^^^^^^^ - -There are two different ways to tell lld which flavor to be. They are checked in -order, so the second overrides the first. The first is to symlink :program:`lld` -as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify -it as the first command line argument using ``-flavor``:: - - $ lld -flavor gnu - -There is a shortcut for ``-flavor core`` as ``-core``. - - -Adding an Option to an existing Flavor -====================================== - -#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`. - -#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method - for the option. - -#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file: - `lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter - for the option. - -#. Modify {Flavor}Reader and {Flavor}Writer to use the new targetInfo option. - - -Adding a Flavor -=============== - -#. Add an entry for the flavor in :file:`include/lld/Common/Driver.h` to - :cpp:class:`lld::UniversalDriver::Flavor`. - -#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to - :cpp:func:`lld::Driver::strToFlavor` and - :cpp:func:`lld::UniversalDriver::link`. - This allows the flavor to be selected via symlink and `-flavor`. - -#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that - describes the options. If the options are a superset of another driver, that - driver's td file can simply be included. The :file:`{flavor}Options.td` file - must also be added to :file:`lib/Driver/CMakeLists.txt`. - -#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver` - in :file:`lib/Driver/{flavor}Driver.cpp`. diff --git a/lld/docs/ELF/linker_script.rst b/lld/docs/ELF/linker_script.rst deleted file mode 100644 index af29996e92..0000000000 --- a/lld/docs/ELF/linker_script.rst +++ /dev/null @@ -1,156 +0,0 @@ -Linker Script implementation notes and policy -============================================= - -LLD implements a large subset of the GNU ld linker script notation. The LLD -implementation policy is to implement linker script features as they are -documented in the ld `manual `_ -We consider it a bug if the lld implementation does not agree with the manual -and it is not mentioned in the exceptions below. - -The ld manual is not a complete specification, and is not sufficient to build -an implementation. In particular some features are only defined by the -implementation and have changed over time. - -The lld implementation policy for properties of linker scripts that are not -defined by the documentation is to follow the GNU ld implementation wherever -possible. We reserve the right to make different implementation choices where -it is appropriate for LLD. Intentional deviations will be documented in this -file. - -Symbol assignment -~~~~~~~~~~~~~~~~~ - -A symbol assignment looks like: - -:: - - symbol = expression; - symbol += expression; - -The first form defines ``symbol``. If ``symbol`` is already defined, it will be -overridden. The other form requires ``symbol`` to be already defined. - -For a simple assignment like ``alias = aliasee;``, the ``st_type`` field is -copied from the original symbol. Any arithmetic operation (e.g. ``+ 0`` will -reset ``st_type`` to ``STT_NOTYPE``. - -The ``st_size`` field is set to 0. - -SECTIONS command -~~~~~~~~~~~~~~~~ - -A ``SECTIONS`` command looks like: - -:: - - SECTIONS { - section-command - section-command - ... - } [INSERT [AFTER|BEFORE] anchor_section;] - -Each section-command can be a symbol assignment, an output section description, -or an overlay description. - -When the ``INSERT`` keyword is present, the ``SECTIONS`` command describes some -output sections which should be inserted after or before the specified anchor -section. The insertion occurs after input sections have been mapped to output -sections but before orphan sections have been processed. - -In the case where no linker script has been provided or every ``SECTIONS`` -command is followed by ``INSERT``, LLD applies built-in rules which are similar -to GNU ld's internal linker scripts. - -- Align the first section in a ``PT_LOAD`` segment according to ``-z noseparate-code``, - ``-z separate-code``, or ``-z separate-loadable-segments`` -- Define ``__bss_start``, ``end``, ``_end``, ``etext``, ``_etext``, ``edata``, ``_edata`` -- Sort ``.ctors.*``/``.dtors.*``/``.init_array.*``/``.fini_array.*`` and PowerPC64 specific ``.toc`` -- Place input ``.text.*`` into output ``.text``, and handle certain variants - (``.text.hot.``, ``.text.unknown.``, ``.text.unlikely.``, etc) in the precense of - ``-z keep-text-section-prefix``. - -Output section description -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The description of an output section looks like: - -:: - - section [address] [(type)] : [AT(lma)] [ALIGN(section_align)] [SUBALIGN](subsection_align)] { - output-section-command - ... - } [>region] [AT>lma_region] [:phdr ...] [=fillexp] [,] - -Output section address ----------------------- - -When an *OutputSection* *S* has ``address``, LLD will set sh_addr to ``address``. - -The ELF specification says: - -> The value of sh_addr must be congruent to 0, modulo the value of sh_addralign. - -The presence of ``address`` can cause the condition unsatisfied. LLD will warn. -GNU ld from Binutils 2.35 onwards will reduce sh_addralign so that -sh_addr=0 (modulo sh_addralign). - -Output section alignment ------------------------- - -sh_addralign of an *OutputSection* *S* is the maximum of -``ALIGN(section_align)`` and the maximum alignment of the input sections in -*S*. - -When an *OutputSection* *S* has both ``address`` and ``ALIGN(section_align)``, -GNU ld will set sh_addralign to ``ALIGN(section_align)``. - -Output section LMA ------------------- - -A load address (LMA) can be specified by ``AT(lma)`` or ``AT>lma_region``. - -- ``AT(lma)`` specifies the exact load address. If the linker script does not - have a PHDRS command, then a new loadable segment will be generated. -- ``AT>lma_region`` specifies the LMA region. The lack of ``AT>lma_region`` - means the default region is used. Note, GNU ld propagates the previous LMA - memory region when ``address`` is not specified. The LMA is set to the - current location of the memory region aligned to the section alignment. - If the linker script does not have a PHDRS command, then if - ``lma_region`` is different from the ``lma_region`` for - the previous OutputSection a new loadable segment will be generated. - -The two keywords cannot be specified at the same time. - -If neither ``AT(lma)`` nor ``AT>lma_region`` is specified: - -- If the previous section is also in the default LMA region, and the two - section have the same memory regions, the difference between the LMA and the - VMA is computed to be the same as the previous difference. -- Otherwise, the LMA is set to the VMA. - -Overwrite sections -~~~~~~~~~~~~~~~~~~ - -An ``OVERWRITE_SECTIONS`` command looks like: - -:: - - OVERWRITE_SECTIONS { - output-section-description - output-section-description - ... - } - -Unlike a ``SECTIONS`` command, ``OVERWRITE_SECTIONS`` does not specify a -section order or suppress the built-in rules. - -If a described output section description also appears in a ``SECTIONS`` -command, the ``OVERWRITE_SECTIONS`` command wins; otherwise, the output section -will be added somewhere following the usual orphan section placement rules. - -If a described output section description also appears in an ``INSERT -[AFTER|BEFORE]`` command, the description will be provided by the -description in the ``OVERWRITE_SECTIONS`` command while the insert command -still applies (possibly after orphan section placement). It is recommended to -leave the brace empty (i.e. ``section : {}``) for the insert command, because -its description will be ignored anyway. diff --git a/lld/docs/ELF/warn_backrefs.rst b/lld/docs/ELF/warn_backrefs.rst deleted file mode 100644 index fac2145cc0..0000000000 --- a/lld/docs/ELF/warn_backrefs.rst +++ /dev/null @@ -1,99 +0,0 @@ ---warn-backrefs -=============== - -``--warn-backrefs`` gives a warning when an undefined symbol reference is -resolved by a definition in an archive to the left of it on the command line. - -A linker such as GNU ld makes a single pass over the input files from left to -right maintaining the set of undefined symbol references from the files loaded -so far. When encountering an archive or an object file surrounded by -``--start-lib`` and ``--end-lib`` that archive will be searched for resolving -symbol definitions; this may result in input files being loaded, updating the -set of undefined symbol references. When all resolving definitions have been -loaded from the archive, the linker moves on the next file and will not return -to it. This means that if an input file to the right of a archive cannot have -an undefined symbol resolved by a archive to the left of it. For example: - - ld def.a ref.o - -will result in an ``undefined reference`` error. If there are no cyclic -references, the archives can be ordered in such a way that there are no -backward references. If there are cyclic references then the ``--start-group`` -and ``--end-group`` options can be used, or the same archive can be placed on -the command line twice. - -LLD remembers the symbol table of archives that it has previously seen, so if -there is a reference from an input file to the right of an archive, LLD will -still search that archive for resolving any undefined references. This means -that an archive only needs to be included once on the command line and the -``--start-group`` and ``--end-group`` options are redundant. - -A consequence of the differing archive searching semantics is that the same -linker command line can result in different outcomes. A link may succeed with -LLD that will fail with GNU ld, or even worse both links succeed but they have -selected different objects from different archives that both define the same -symbols. - -The ``warn-backrefs`` option provides information that helps identify cases -where LLD and GNU ld archive selection may differ. - - | % ld.lld --warn-backrefs ... -lB -lA - | ld.lld: warning: backward reference detected: system in A.a(a.o) refers to B.a(b.o) - - | % ld.lld --warn-backrefs ... --start-lib B/b.o --end-lib --start-lib A/a.o --end-lib - | ld.lld: warning: backward reference detected: system in A/a.o refers to B/b.o - - # To suppress the warning, you can specify --warn-backrefs-exclude= to match B/b.o or B.a(b.o) - -The ``--warn-backrefs`` option can also provide a check to enforce a -topological order of archives, which can be useful to detect layering -violations (albeit unable to catch all cases). There are two cases where GNU ld -will result in an ``undefined reference`` error: - -* If adding the dependency does not form a cycle: conceptually ``A`` is higher - level library while ``B`` is at a lower level. When you are developing an - application ``P`` which depends on ``A``, but does not directly depend on - ``B``, your link may fail surprisingly with ``undefined symbol: - symbol_defined_in_B`` if the used/linked part of ``A`` happens to need some - components of ``B``. It is inappropriate for ``P`` to add a dependency on - ``B`` since ``P`` does not use ``B`` directly. -* If adding the dependency forms a cycle, e.g. ``B->C->A ~> B``. ``A`` - is supposed to be at the lowest level while ``B`` is supposed to be at the - highest level. When you are developing ``C_test`` testing ``C``, your link may - fail surprisingly with ``undefined symbol`` if there is somehow a dependency on - some components of ``B``. You could fix the issue by adding the missing - dependency (``B``), however, then every test (``A_test``, ``B_test``, - ``C_test``) will link against every library. This breaks the motivation - of splitting ``B``, ``C`` and ``A`` into separate libraries and makes binaries - unnecessarily large. Moreover, the layering violation makes lower-level - libraries (e.g. ``A``) vulnerable to changes to higher-level libraries (e.g. - ``B``, ``C``). - -Resolution: - -* Add a dependency from ``A`` to ``B``. -* The reference may be unintended and can be removed. -* The dependency may be intentionally omitted because there are multiple - libraries like ``B``. Consider linking ``B`` with object semantics by - surrounding it with ``--whole-archive`` and ``--no-whole-archive``. -* In the case of circular dependency, sometimes merging the libraries are the best. - -There are two cases like a library sandwich where GNU ld will select a -different object. - -* ``A.a B A2.so``: ``A.a`` may be used as an interceptor (e.g. it provides some - optimized libc functions and ``A2`` is libc). ``B`` does not need to know - about ``A.a``, and ``A.a`` may be pulled into the link by other part of the - program. For linker portability, consider ``--whole-archive`` and - ``--no-whole-archive``. - -* ``A.a B A2.a``: similar to the above case but ``--warn-backrefs`` does not - flag the problem, because ``A2.a`` may be a replicate of ``A.a``, which is - redundant but benign. In some cases ``A.a`` and ``B`` should be surrounded by - a pair of ``--start-group`` and ``--end-group``. This is especially common - among system libraries (e.g. ``-lc __isnanl references -lm``, ``-lc - _IO_funlockfile references -lpthread``, ``-lc __gcc_personality_v0 references - -lgcc_eh``, and ``-lpthread _Unwind_GetCFA references -lunwind``). - - In C++, this is likely an ODR violation. We probably need a dedicated option - for ODR detection. diff --git a/lld/docs/NewLLD.rst b/lld/docs/NewLLD.rst deleted file mode 100644 index 1b1c87067f..0000000000 --- a/lld/docs/NewLLD.rst +++ /dev/null @@ -1,317 +0,0 @@ -The ELF, COFF and Wasm Linkers -============================== - -The ELF Linker as a Library ---------------------------- - -You can embed LLD to your program by linking against it and calling the linker's -entry point function lld::elf::link. - -The current policy is that it is your responsibility to give trustworthy object -files. The function is guaranteed to return as long as you do not pass corrupted -or malicious object files. A corrupted file could cause a fatal error or SEGV. -That being said, you don't need to worry too much about it if you create object -files in the usual way and give them to the linker. It is naturally expected to -work, or otherwise it's a linker's bug. - -Design -====== - -We will describe the design of the linkers in the rest of the document. - -Key Concepts ------------- - -Linkers are fairly large pieces of software. -There are many design choices you have to make to create a complete linker. - -This is a list of design choices we've made for ELF and COFF LLD. -We believe that these high-level design choices achieved a right balance -between speed, simplicity and extensibility. - -* Implement as native linkers - - We implemented the linkers as native linkers for each file format. - - The linkers share the same design but share very little code. - Sharing code makes sense if the benefit is worth its cost. - In our case, the object formats are different enough that we thought the layer - to abstract the differences wouldn't be worth its complexity and run-time - cost. Elimination of the abstract layer has greatly simplified the - implementation. - -* Speed by design - - One of the most important things in archiving high performance is to - do less rather than do it efficiently. - Therefore, the high-level design matters more than local optimizations. - Since we are trying to create a high-performance linker, - it is very important to keep the design as efficient as possible. - - Broadly speaking, we do not do anything until we have to do it. - For example, we do not read section contents or relocations - until we need them to continue linking. - When we need to do some costly operation (such as looking up - a hash table for each symbol), we do it only once. - We obtain a handle (which is typically just a pointer to actual data) - on the first operation and use it throughout the process. - -* Efficient archive file handling - - LLD's handling of archive files (the files with ".a" file extension) is - different from the traditional Unix linkers and similar to Windows linkers. - We'll describe how the traditional Unix linker handles archive files, what the - problem is, and how LLD approached the problem. - - The traditional Unix linker maintains a set of undefined symbols during - linking. The linker visits each file in the order as they appeared in the - command line until the set becomes empty. What the linker would do depends on - file type. - - - If the linker visits an object file, the linker links object files to the - result, and undefined symbols in the object file are added to the set. - - - If the linker visits an archive file, it checks for the archive file's - symbol table and extracts all object files that have definitions for any - symbols in the set. - - This algorithm sometimes leads to a counter-intuitive behavior. If you give - archive files before object files, nothing will happen because when the linker - visits archives, there is no undefined symbols in the set. As a result, no - files are extracted from the first archive file, and the link is done at that - point because the set is empty after it visits one file. - - You can fix the problem by reordering the files, - but that cannot fix the issue of mutually-dependent archive files. - - Linking mutually-dependent archive files is tricky. You may specify the same - archive file multiple times to let the linker visit it more than once. Or, - you may use the special command line options, `--start-group` and - `--end-group`, to let the linker loop over the files between the options until - no new symbols are added to the set. - - Visiting the same archive files multiple times makes the linker slower. - - Here is how LLD approaches the problem. Instead of memorizing only undefined - symbols, we program LLD so that it memorizes all symbols. When it sees an - undefined symbol that can be resolved by extracting an object file from an - archive file it previously visited, it immediately extracts the file and links - it. It is doable because LLD does not forget symbols it has seen in archive - files. - - We believe that LLD's way is efficient and easy to justify. - - The semantics of LLD's archive handling are different from the traditional - Unix's. You can observe it if you carefully craft archive files to exploit - it. However, in reality, we don't know any program that cannot link with our - algorithm so far, so it's not going to cause trouble. - -Numbers You Want to Know ------------------------- - -To give you intuition about what kinds of data the linker is mainly working on, -I'll give you the list of objects and their numbers LLD has to read and process -in order to link a very large executable. In order to link Chrome with debug -info, which is roughly 2 GB in output size, LLD reads - -- 17,000 files, -- 1,800,000 sections, -- 6,300,000 symbols, and -- 13,000,000 relocations. - -LLD produces the 2 GB executable in 15 seconds. - -These numbers vary depending on your program, but in general, -you have a lot of relocations and symbols for each file. -If your program is written in C++, symbol names are likely to be -pretty long because of name mangling. - -It is important to not waste time on relocations and symbols. - -In the above case, the total amount of symbol strings is 450 MB, -and inserting all of them to a hash table takes 1.5 seconds. -Therefore, if you causally add a hash table lookup for each symbol, -it would slow down the linker by 10%. So, don't do that. - -On the other hand, you don't have to pursue efficiency -when handling files. - -Important Data Structures -------------------------- - -We will describe the key data structures in LLD in this section. The linker can -be understood as the interactions between them. Once you understand their -functions, the code of the linker should look obvious to you. - -* Symbol - - This class represents a symbol. - They are created for symbols in object files or archive files. - The linker creates linker-defined symbols as well. - - There are basically three types of Symbols: Defined, Undefined, or Lazy. - - - Defined symbols are for all symbols that are considered as "resolved", - including real defined symbols, COMDAT symbols, common symbols, - absolute symbols, linker-created symbols, etc. - - Undefined symbols represent undefined symbols, which need to be replaced by - Defined symbols by the resolver until the link is complete. - - Lazy symbols represent symbols we found in archive file headers - which can turn into Defined if we read archive members. - - There's only one Symbol instance for each unique symbol name. This uniqueness - is guaranteed by the symbol table. As the resolver reads symbols from input - files, it replaces an existing Symbol with the "best" Symbol for its symbol - name using the placement new. - - The above mechanism allows you to use pointers to Symbols as a very cheap way - to access name resolution results. Assume for example that you have a pointer - to an undefined symbol before name resolution. If the symbol is resolved to a - defined symbol by the resolver, the pointer will "automatically" point to the - defined symbol, because the undefined symbol the pointer pointed to will have - been replaced by the defined symbol in-place. - -* SymbolTable - - SymbolTable is basically a hash table from strings to Symbols - with logic to resolve symbol conflicts. It resolves conflicts by symbol type. - - - If we add Defined and Undefined symbols, the symbol table will keep the - former. - - If we add Defined and Lazy symbols, it will keep the former. - - If we add Lazy and Undefined, it will keep the former, - but it will also trigger the Lazy symbol to load the archive member - to actually resolve the symbol. - -* Chunk (COFF specific) - - Chunk represents a chunk of data that will occupy space in an output. - Each regular section becomes a chunk. - Chunks created for common or BSS symbols are not backed by sections. - The linker may create chunks to append additional data to an output as well. - - Chunks know about their size, how to copy their data to mmap'ed outputs, - and how to apply relocations to them. - Specifically, section-based chunks know how to read relocation tables - and how to apply them. - -* InputSection (ELF specific) - - Since we have less synthesized data for ELF, we don't abstract slices of - input files as Chunks for ELF. Instead, we directly use the input section - as an internal data type. - - InputSection knows about their size and how to copy themselves to - mmap'ed outputs, just like COFF Chunks. - -* OutputSection - - OutputSection is a container of InputSections (ELF) or Chunks (COFF). - An InputSection or Chunk belongs to at most one OutputSection. - -There are mainly three actors in this linker. - -* InputFile - - InputFile is a superclass of file readers. - We have a different subclass for each input file type, - such as regular object file, archive file, etc. - They are responsible for creating and owning Symbols and InputSections/Chunks. - -* Writer - - The writer is responsible for writing file headers and InputSections/Chunks to - a file. It creates OutputSections, put all InputSections/Chunks into them, - assign unique, non-overlapping addresses and file offsets to them, and then - write them down to a file. - -* Driver - - The linking process is driven by the driver. The driver: - - - processes command line options, - - creates a symbol table, - - creates an InputFile for each input file and puts all symbols within into - the symbol table, - - checks if there's no remaining undefined symbols, - - creates a writer, - - and passes the symbol table to the writer to write the result to a file. - -Link-Time Optimization ----------------------- - -LTO is implemented by handling LLVM bitcode files as object files. -The linker resolves symbols in bitcode files normally. If all symbols -are successfully resolved, it then runs LLVM passes -with all bitcode files to convert them to one big regular ELF/COFF file. -Finally, the linker replaces bitcode symbols with ELF/COFF symbols, -so that they are linked as if they were in the native format from the beginning. - -The details are described in this document. -https://llvm.org/docs/LinkTimeOptimization.html - -Glossary --------- - -* RVA (COFF) - - Short for Relative Virtual Address. - - Windows executables or DLLs are not position-independent; they are - linked against a fixed address called an image base. RVAs are - offsets from an image base. - - Default image bases are 0x140000000 for executables and 0x18000000 - for DLLs. For example, when we are creating an executable, we assume - that the executable will be loaded at address 0x140000000 by the - loader, so we apply relocations accordingly. Result texts and data - will contain raw absolute addresses. - -* VA - - Short for Virtual Address. For COFF, it is equivalent to RVA + image base. - -* Base relocations (COFF) - - Relocation information for the loader. If the loader decides to map - an executable or a DLL to a different address than their image - bases, it fixes up binaries using information contained in the base - relocation table. A base relocation table consists of a list of - locations containing addresses. The loader adds a difference between - RVA and actual load address to all locations listed there. - - Note that this run-time relocation mechanism is much simpler than ELF. - There's no PLT or GOT. Images are relocated as a whole just - by shifting entire images in memory by some offsets. Although doing - this breaks text sharing, I think this mechanism is not actually bad - on today's computers. - -* ICF - - Short for Identical COMDAT Folding (COFF) or Identical Code Folding (ELF). - - ICF is an optimization to reduce output size by merging read-only sections - by not only their names but by their contents. If two read-only sections - happen to have the same metadata, actual contents and relocations, - they are merged by ICF. It is known as an effective technique, - and it usually reduces C++ program's size by a few percent or more. - - Note that this is not an entirely sound optimization. C/C++ require - different functions have different addresses. If a program depends on - that property, it would fail at runtime. - - On Windows, that's not really an issue because MSVC link.exe enabled - the optimization by default. As long as your program works - with the linker's default settings, your program should be safe with ICF. - - On Unix, your program is generally not guaranteed to be safe with ICF, - although large programs happen to work correctly. - LLD works fine with ICF for example. - -Other Info ----------- - -.. toctree:: - :maxdepth: 1 - - missingkeyfunction diff --git a/lld/docs/Partitions.rst b/lld/docs/Partitions.rst deleted file mode 100644 index e911308763..0000000000 --- a/lld/docs/Partitions.rst +++ /dev/null @@ -1,116 +0,0 @@ -Partitions -========== - -.. warning:: - - This feature is currently experimental, and its interface is subject - to change. - -LLD's partitioning feature allows a program (which may be an executable -or a shared library) to be split into multiple pieces, or partitions. A -partitioned program consists of a main partition together with a number of -loadable partitions. The loadable partitions depend on the main partition -in a similar way to a regular ELF shared object dependency, but unlike a -shared object, the main partition and the loadable partitions share a virtual -address space at link time, and each loadable partition is assigned a fixed -offset from the main partition. This allows the loadable partitions to refer -to code and data in the main partition directly without the binary size and -performance overhead of PLTs, GOTs or symbol table entries. - -Usage ------ - -A program that uses the partitioning feature must decide which symbols are -going to be used as the "entry points" for each partition. An entry point -could, for example, be the equivalent of the partition's ``main`` function, or -there could be a group of functions that expose the functionality implemented -by the partition. The intent is that in order to use a loadable partition, -the program will use ``dlopen``/``dlsym`` or similar functions to dynamically -load the partition at its assigned address, look up an entry point by name -and call it. Note, however, that the standard ``dlopen`` function does not -allow specifying a load address. On Android, the ``android_dlopen_ext`` -function may be used together with the ``ANDROID_DLEXT_RESERVED_ADDRESS`` -flag to load a shared object at a specific address. - -Once the entry points have been decided, the translation unit(s) -containing the entry points should be compiled using the Clang compiler flag -``-fsymbol-partition=``, where ```` is the intended soname -of the partition. The resulting object files are passed to the linker in -the usual way. - -The linker will then use these entry points to automatically split the program -into partitions according to which sections of the program are reachable from -which entry points, similarly to how ``--gc-sections`` removes unused parts of -a program. Any sections that are only reachable from a loadable partition's -entry point are assigned to that partition, while all other sections are -assigned to the main partition, including sections only reachable from -loadable partitions. - -The following diagram illustrates how sections are assigned to partitions. Each -section is colored according to its assigned partition. - -.. image:: partitions.svg - -The result of linking a program that uses partitions is essentially an -ELF file with all of the partitions concatenated together. This file is -referred to as a combined output file. To extract a partition from the -combined output file, the ``llvm-objcopy`` tool should be used together -with the flag ``--extract-main-partition`` to extract the main partition, or -``-extract-partition=`` to extract one of the loadable partitions. -An example command sequence is shown below: - -.. code-block:: shell - - # Compile the main program. - clang -ffunction-sections -fdata-sections -c main.c - - # Compile a feature to be placed in a loadable partition. - # Note that this is likely to be a separate build step to the main partition. - clang -ffunction-sections -fdata-sections -fsymbol-partition=libfeature.so -c feature.c - - # Link the combined output file. - clang main.o feature.o -fuse-ld=lld -shared -o libcombined.so -Wl,-soname,libmain.so -Wl,--gc-sections - - # Extract the partitions. - llvm-objcopy libcombined.so libmain.so --extract-main-partition - llvm-objcopy libcombined.so libfeature.so --extract-partition=libfeature.so - -In order to allow a program to discover the names of its loadable partitions -and the locations of their reserved regions, the linker creates a partition -index, which is an array of structs with the following definition: - -.. code-block:: c - - struct partition_index_entry { - int32_t name_offset; - int32_t addr_offset; - uint32_t size; - }; - -The ``name_offset`` field is a relative pointer to a null-terminated string -containing the soname of the partition, the ``addr_offset`` field is a -relative pointer to its load address and the ``size`` field contains the -size of the region reserved for the partition. To derive an absolute pointer -from the relative pointer fields in this data structure, the address of the -field should be added to the value stored in the field. - -The program may discover the location of the partition index using the -linker-defined symbols ``__part_index_begin`` and ``__part_index_end``. - -Restrictions ------------- - -This feature is currently only supported in the ELF linker. - -The partitioning feature may not currently be used together with the -``SECTIONS`` or ``PHDRS`` linker script features, nor may it be used with the -``--section-start``, ``-Ttext``, ``-Tdata`` or ``-Tbss`` flags. All of these -features assume a single set of output sections and/or program headers, which -makes their semantics ambiguous in the presence of more than one partition. - -The partitioning feature may not currently be used on the MIPS architecture -because it is unclear whether the MIPS multi-GOT ABI is compatible with -partitions. - -The current implementation only supports creating up to 254 partitions due -to implementation limitations. This limit may be relaxed in the future. diff --git a/lld/docs/README.txt b/lld/docs/README.txt deleted file mode 100644 index 2ed016639d..0000000000 --- a/lld/docs/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -lld Documentation -================= - -The lld documentation is written using the Sphinx documentation generator. It is -currently tested with Sphinx 1.1.3. - -We currently use the 'nature' theme and a Beaker inspired structure. - -See sphinx_intro.rst for more details. diff --git a/lld/docs/Readers.rst b/lld/docs/Readers.rst deleted file mode 100644 index eae1717f6e..0000000000 --- a/lld/docs/Readers.rst +++ /dev/null @@ -1,174 +0,0 @@ -.. _Readers: - -Developing lld Readers -====================== - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -Introduction ------------- - -The purpose of a "Reader" is to take an object file in a particular format -and create an `lld::File`:cpp:class: (which is a graph of Atoms) -representing the object file. A Reader inherits from -`lld::Reader`:cpp:class: which lives in -:file:`include/lld/Core/Reader.h` and -:file:`lib/Core/Reader.cpp`. - -The Reader infrastructure for an object format ``Foo`` requires the -following pieces in order to fit into lld: - -:file:`include/lld/ReaderWriter/ReaderFoo.h` - - .. cpp:class:: ReaderOptionsFoo : public ReaderOptions - - This Options class is the only way to configure how the Reader will - parse any file into an `lld::Reader`:cpp:class: object. This class - should be declared in the `lld`:cpp:class: namespace. - - .. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader) - - This factory function configures and create the Reader. This function - should be declared in the `lld`:cpp:class: namespace. - -:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp` - - .. cpp:class:: ReaderFoo : public Reader - - This is the concrete Reader class which can be called to parse - object files. It should be declared in an anonymous namespace or - if there is shared code with the `lld::WriterFoo`:cpp:class: you - can make a nested namespace (e.g. `lld::foo`:cpp:class:). - -You may have noticed that :cpp:class:`ReaderFoo` is not declared in the -``.h`` file. An important design aspect of lld is that all Readers are -created *only* through an object-format-specific -:cpp:func:`createReaderFoo` factory function. The creation of the Reader is -parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options -class is the one-and-only way to control how the Reader operates when -parsing an input file into an Atom graph. For instance, you may want the -Reader to only accept certain architectures. The options class can be -instantiated from command line options or be programmatically configured. - -Where to start --------------- - -The lld project already has a skeleton of source code for Readers for -``ELF``, ``PECOFF``, ``MachO``, and lld's native ``YAML`` graph format. -If your file format is a variant of one of those, you should modify the -existing Reader to support your variant. This is done by customizing the Options -class for the Reader and making appropriate changes to the ``.cpp`` file to -interpret those options and act accordingly. - -If your object file format is not a variant of any existing Reader, you'll need -to create a new Reader subclass with the organization described above. - -Readers are factories ---------------------- - -The linker will usually only instantiate your Reader once. That one Reader will -have its loadFile() method called many times with different input files. -To support multithreaded linking, the Reader may be parsing multiple input -files in parallel. Therefore, there should be no parsing state in you Reader -object. Any parsing state should be in ivars of your File subclass or in -some temporary object. - -The key function to implement in a reader is:: - - virtual error_code loadFile(LinkerInput &input, - std::vector> &result); - -It takes a memory buffer (which contains the contents of the object file -being read) and returns an instantiated lld::File object which is -a collection of Atoms. The result is a vector of File pointers (instead of -simple a File pointer) because some file formats allow multiple object -"files" to be encoded in one file system file. - - -Memory Ownership ----------------- - -Atoms are always owned by their File object. During core linking when Atoms -are coalesced or stripped away, core linking does not delete them. -Core linking just removes those unused Atoms from its internal list. -The destructor of a File object is responsible for deleting all Atoms it -owns, and if ownership of the MemoryBuffer was passed to it, the File -destructor needs to delete that too. - -Making Atoms ------------- - -The internal model of lld is purely Atom based. But most object files do not -have an explicit concept of Atoms, instead most have "sections". The way -to think of this is that a section is just a list of Atoms with common -attributes. - -The first step in parsing section-based object files is to cleave each -section into a list of Atoms. The technique may vary by section type. For -code sections (e.g. .text), there are usually symbols at the start of each -function. Those symbol addresses are the points at which the section is -cleaved into discrete Atoms. Some file formats (like ELF) also include the -length of each symbol in the symbol table. Otherwise, the length of each -Atom is calculated to run to the start of the next symbol or the end of the -section. - -Other sections types can be implicitly cleaved. For instance c-string literals -or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at -the content of the section. It is important to cleave sections into Atoms -to remove false dependencies. For instance the .eh_frame section often -has no symbols, but contains "pointers" to the functions for which it -has unwind info. If the .eh_frame section was not cleaved (but left as one -big Atom), there would always be a reference (from the eh_frame Atom) to -each function. So the linker would be unable to coalesce or dead stripped -away the function atoms. - -The lld Atom model also requires that a reference to an undefined symbol be -modeled as a Reference to an UndefinedAtom. So the Reader also needs to -create an UndefinedAtom for each undefined symbol in the object file. - -Once all Atoms have been created, the second step is to create References -(recall that Atoms are "nodes" and References are "edges"). Most References -are created by looking at the "relocation records" in the object file. If -a function contains a call to "malloc", there is usually a relocation record -specifying the address in the section and the symbol table index. Your -Reader will need to convert the address to an Atom and offset and the symbol -table index into a target Atom. If "malloc" is not defined in the object file, -the target Atom of the Reference will be an UndefinedAtom. - - -Performance ------------ -Once you have the above working to parse an object file into Atoms and -References, you'll want to look at performance. Some techniques that can -help performance are: - -* Use llvm::BumpPtrAllocator or pre-allocate one big vector and then - just have each atom point to its subrange of References in that vector. - This can be faster that allocating each Reference as separate object. -* Pre-scan the symbol table and determine how many atoms are in each section - then allocate space for all the Atom objects at once. -* Don't copy symbol names or section content to each Atom, instead use - StringRef and ArrayRef in each Atom to point to its name and content in the - MemoryBuffer. - - -Testing -------- - -We are still working on infrastructure to test Readers. The issue is that -you don't want to check in binary files to the test suite. And the tools -for creating your object file from assembly source may not be available on -every OS. - -We are investigating a way to use YAML to describe the section, symbols, -and content of a file. Then have some code which will write out an object -file from that YAML description. - -Once that is in place, you can write test cases that contain section/symbols -YAML and is run through the linker to produce Atom/References based YAML which -is then run through FileCheck to verify the Atoms and References are as -expected. - - - diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst deleted file mode 100644 index 238bf5a9f6..0000000000 --- a/lld/docs/ReleaseNotes.rst +++ /dev/null @@ -1,188 +0,0 @@ -======================== -lld 13.0.0 Release Notes -======================== - -.. contents:: - :local: - -Introduction -============ - -This document contains the release notes for the lld linker, release 13.0.0. -Here we describe the status of lld, including major improvements -from the previous release. All lld releases may be downloaded -from the `LLVM releases web site `_. - -Non-comprehensive list of changes in this release -================================================= - -ELF Improvements ----------------- - -* ``-z start-stop-gc`` is now supported and becomes the default. - (`D96914 `_) - (`rG6d2d3bd0 `_) -* ``--shuffle-sections=`` has been changed to ``--shuffle-sections==``. - If seed is -1, the matched input sections are reversed. - (`D98445 `_) - (`D98679 `_) -* ``-Bsymbolic -Bsymbolic-functions`` has been changed to behave the same as ``-Bsymbolic-functions``. This matches GNU ld. - (`D102461 `_) -* ``-Bno-symbolic`` has been added. - (`D102461 `_) -* A new linker script command ``OVERWRITE_SECTIONS`` has been added. - (`D103303 `_) -* ``-Bsymbolic-non-weak-functions`` has been added as a ``STB_GLOBAL`` subset of ``-Bsymbolic-functions``. - (`D102570 `_) -* ``--no-allow-shlib-undefined`` has been improved to catch more cases. - (`D101996 `_) -* ``__rela_iplt_start`` is no longer defined for -pie/-shared. - This makes GCC/Clang ``-static-pie`` built executables work. - (`rG8cb78e99 `_) -* IRELATIVE/TLSDESC relocations now support ``-z rel``. - (`D100544 `_) -* Section groups with a zero flag are now supported. - This is used by ``comdat nodeduplicate`` in LLVM IR. - (`D96636 `_) - (`D106228 `_) -* Defined symbols are now resolved before undefined symbols to stabilize the bheavior of archive member extraction. - (`D95985 `_) -* ``STB_WEAK`` symbols are now preferred over COMMON symbols as a fix to a ``--fortran-common`` regression. - (`D105945 `_) -* Absolute relocations referencing undef weak now produce dynamic relocations for -pie, matching GOT-generating relocations. - (`D105164 `_) -* Exported symbols are now communicated to the LTO library so as to make LTO - based whole program devirtualization (``-flto=thin -fwhole-program-vtables``) - work with shared objects. - (`D91583 `_) -* Whole program devirtualization now respects ``local:`` version nodes in a version script. - (`D98220 `_) - (`D98686 `_) -* ``local:`` version nodes in a version script now apply to non-default version symbols. - (`D107234 `_) -* If an object file defines both ``foo`` and ``foo@v1``, now only ``foo@v1`` will be in the output. - (`D107235 `_) -* Copy relocations on non-default version symbols are now supported. - (`D107535 `_) - -Linker script changes: - -* ``.``, ``$``, and double quotes can now be used in symbol names in expressions. - (`D98306 `_) - (`rGe7a7ad13 `_) -* Fixed value of ``.`` in the output section description of ``.tbss``. - (`D107288 `_) -* ``NOLOAD`` sections can now be placed in a ``PT_LOAD`` program header. - (`D103815 `_) -* ``OUTPUT_FORMAT(default, big, little)`` now consults ``-EL`` and ``-EB``. - (`D96214 `_) -* The ``OVERWRITE_SECTIONS`` command has been added. - (`D103303 `_) -* The section order within an ``INSERT AFTER`` command is now preserved. - (`D105158 `_) - -Architecture specific changes: - -* aarch64_be is now supported. - (`D96188 `_) -* The AMDGPU port now supports ``--amdhsa-code-object-version=4`` object files; - (`D95811 `_) -* The ARM port now accounts for PC biases in range extension thunk creation. - (`D97550 `_) -* The AVR port now computes ``e_flags``. - (`D99754 `_) -* The Mips port now omits unneeded dynamic relocations for PIE non-preemptible TLS. - (`D101382 `_) -* The PowerPC port now supports ``--power10-stubs=no`` to omit Power10 instructions from call stubs. - (`D94625 `_) -* Fixed a thunk creation bug in the PowerPC port when TOC/NOTOC calls are mixed. - (`D101837 `_) -* The RISC-V port now resolves undefined weak relocations to the current location if not using PLT. - (`D103001 `_) -* ``R_386_GOTOFF`` relocations from .debug_info are now allowed to be compatible with GCC. - (`D95994 `_) -* ``gotEntrySize`` has been added to improve support for the ILP32 ABI of x86-64. - (`D102569 `_) - -Breaking changes ----------------- - -* ``--shuffle-sections=`` has been changed to ``--shuffle-sections==``. - Specify ``*`` as ```` to get the previous behavior. - -COFF Improvements ------------------ - -* Avoid thread exhaustion when running on 32 bit Windows. - (`D105506 `_) - -* Improve terminating the process on Windows while a thread pool might be - running. (`D102944 `_) - -MinGW Improvements ------------------- - -* Support for linking directly against a DLL without using an import library - has been added. (`D104530 `_ and - `D104531 `_) - -* Fix linking with ``--export-all-symbols`` in combination with - ``-function-sections``. (`D101522 `_ and - `D101615 `_) - -* Fix automatic export of symbols from LTO objects. - (`D101569 `_) - -* Accept more spellings of some options. - (`D107237 `_ and - `D107253 `_) - -Mach-O Improvements -------------------- - -The Mach-O backend is now able to link several large, real-world programs, -though we are still working out the kinks. - -* arm64 is now supported as a target. (`D88629 `_) -* arm64_32 is now supported as a target. (`D99822 `_) -* Branch-range-extension thunks are now supported. (`D100818 `_) -* ``-dead_strip`` is now supported. (`D103324 `_) -* Support for identical code folding (``--icf=all``) has been added. - (`D103292 `_) -* Support for special ``$start`` and ``$end`` symbols for segment & sections has been - added. (`D106767 `_, `D106629 `_) -* ``$ld$previous`` symbols are now supported. (`D103505 `_) -* ``$ld$install_name`` symbols are now supported. (`D103746 `_) -* ``__mh_*_header`` symbols are now supported. (`D97007 `_) -* LC_CODE_SIGNATURE is now supported. (`D96164 `_) -* LC_FUNCTION_STARTS is now supported. (`D97260 `_) -* LC_DATA_IN_CODE is now supported. (`D103006 `_) -* Bind opcodes are more compactly encoded. (`D106128 `_, - `D105075 `_) -* LTO cache support has been added. (`D105922 `_) -* ``-application_extension`` is now supported. (`D105818 `_) -* ``-export_dynamic`` is now partially supported. (`D105482 `_) -* ``-arch_multiple`` is now supported. (`D105450 `_) -* ``-final_output`` is now supported. (`D105449 `_) -* ``-umbrella`` is now supported. (`D105448 `_) -* ``--print-dylib-search`` is now supported. (`D103985 `_) -* ``-force_load_swift_libs`` is now supported. (`D103709 `_) -* ``-reexport_framework``, ``-reexport_library``, ``-reexport-l`` are now supported. - (`D103497 `_) -* ``.weak_def_can_be_hidden`` is now supported. (`D101080 `_) -* ``-add_ast_path`` is now supported. (`D100076 `_) -* ``-segprot`` is now supported. (`D99389 `_) -* ``-dependency_info`` is now partially supported. (`D98559 `_) -* ``--time-trace`` is now supported. (`D98419 `_) -* ``-mark_dead_strippable_dylib`` is now supported. (`D98262 `_) -* ``-[un]exported_symbol[s_list]`` is now supported. (`D98223 `_) -* ``-flat_namespace`` is now supported. (`D97641 `_) -* ``-rename_section`` and ``-rename_segment`` are now supported. (`D97600 `_) -* ``-bundle_loader`` is now supported. (`D95913 `_) -* ``-map`` is now partially supported. (`D98323 `_) - -There were numerous other bug-fixes as well. - -WebAssembly Improvements ------------------------- - diff --git a/lld/docs/WebAssembly.rst b/lld/docs/WebAssembly.rst deleted file mode 100644 index c01df99cdd..0000000000 --- a/lld/docs/WebAssembly.rst +++ /dev/null @@ -1,210 +0,0 @@ -WebAssembly lld port -==================== - -The WebAssembly version of lld takes WebAssembly binaries as inputs and produces -a WebAssembly binary as its output. For the most part it tries to mimic the -behaviour of traditional ELF linkers and specifically the ELF lld port. Where -possible the command line flags and the semantics should be the same. - - -Object file format ------------------- - -The WebAssembly object file format used by LLVM and LLD is specified as part of -the WebAssembly tool conventions on linking_. - -This is the object format that the llvm will produce when run with the -``wasm32-unknown-unknown`` target. - -Usage ------ - -The WebAssembly version of lld is installed as **wasm-ld**. It shared many -common linker flags with **ld.lld** but also includes several -WebAssembly-specific options: - -.. option:: --no-entry - - Don't search for the entry point symbol (by default ``_start``). - -.. option:: --export-table - - Export the function table to the environment. - -.. option:: --import-table - - Import the function table from the environment. - -.. option:: --export-all - - Export all symbols (normally combined with --no-gc-sections) - - Note that this will not export linker-generated mutable globals unless - the resulting binaryen already includes the 'mutable-globals' features - since that would otherwise create and invalid binaryen. - -.. option:: --export-dynamic - - When building an executable, export any non-hidden symbols. By default only - the entry point and any symbols marked as exports (either via the command line - or via the `export-name` source attribute) are exported. - -.. option:: --global-base= - - Address at which to place global data. - -.. option:: --no-merge-data-segments - - Disable merging of data segments. - -.. option:: --stack-first - - Place stack at start of linear memory rather than after data. - -.. option:: --compress-relocations - - Relocation targets in the code section are 5-bytes wide in order to - potentially accommodate the largest LEB128 value. This option will cause the - linker to shrink the code section to remove any padding from the final - output. However because it affects code offset, this option is not - compatible with outputting debug information. - -.. option:: --allow-undefined - - Allow undefined symbols in linked binary. This is the legacy - flag which corresponds to ``--unresolve-symbols=ignore`` + - ``--import-undefined``. - -.. option:: --unresolved-symbols= - - This is a more full featured version of ``--allow-undefined``. - The semanatics of the different methods are as follows: - - report-all: - - Report all unresolved symbols. This is the default. Normally the linker - will generate an error message for each reported unresolved symbol but the - option ``--warn-unresolved-symbols`` can change this to a warning. - - ignore-all: - - Resolve all undefined symbols to zero. For data and function addresses - this is trivial. For direct function calls, the linker will generate a - trapping stub function in place of the undefined function. - -.. option:: --import-memory - - Import memory from the environment. - -.. option:: --import-undefined - - Generate WebAssembly imports for undefined symbols, where possible. For - example, for function symbols this is always possible, but in general this - is not possible for undefined data symbols. Undefined data symbols will - still be reported as normal (in accordance with ``--unresolved-symbols``). - -.. option:: --initial-memory= - - Initial size of the linear memory. Default: static data size. - -.. option:: --max-memory= - - Maximum size of the linear memory. Default: unlimited. - -By default the function table is neither imported nor exported, but defined -for internal use only. - -Behaviour ---------- - -In general, where possible, the WebAssembly linker attempts to emulate the -behaviour of a traditional ELF linker, and in particular the ELF port of lld. -For more specific details on how this is achieved see the tool conventions on -linking_. - -Function Signatures -~~~~~~~~~~~~~~~~~~~ - -One way in which the WebAssembly linker differs from traditional native linkers -is that function signature checking is strict in WebAssembly. It is a -validation error for a module to contain a call site that doesn't agree with -the target signature. Even though this is undefined behaviour in C/C++, it is not -uncommon to find this in real-world C/C++ programs. For example, a call site in -one compilation unit which calls a function defined in another compilation -unit but with too many arguments. - -In order not to generate such invalid modules, lld has two modes of handling such -mismatches: it can simply error-out or it can create stub functions that will -trap at runtime (functions that contain only an ``unreachable`` instruction) -and use these stub functions at the otherwise invalid call sites. - -The default behaviour is to generate these stub function and to produce -a warning. The ``--fatal-warnings`` flag can be used to disable this behaviour -and error out if mismatched are found. - -Exports -~~~~~~~ - -When building a shared library any symbols marked as ``visibility=default`` will -be exported. - -When building an executable, only the entry point (``_start``) and symbols with -the ``WASM_SYMBOL_EXPORTED`` flag are exported by default. In LLVM the -``WASM_SYMBOL_EXPORTED`` flag is set by the ``wasm-export-name`` attribute which -in turn can be set using ``__attribute__((export_name))`` clang attribute. - -In addition, symbols can be exported via the linker command line using -``--export`` (which will error if the symbol is not found) or -``--export-if-defined`` (which will not). - -Finally, just like with native ELF linker the ``--export-dynamic`` flag can be -used to export symbols in the executable which are marked as -``visibility=default``. - -Imports -~~~~~~~ - -By default no undefined symbols are allowed in the final binary. The flag -``--allow-undefined`` results in a WebAssembly import being defined for each -undefined symbol. It is then up to the runtime to provide such symbols. - -Alternatively symbols can be marked in the source code as with the -``import_name`` and/or ``import_module`` clang attributes which signals that -they are expected to be undefined at static link time. - -Garbage Collection -~~~~~~~~~~~~~~~~~~ - -Since WebAssembly is designed with size in mind the linker defaults to -``--gc-sections`` which means that all unused functions and data segments will -be stripped from the binary. - -The symbols which are preserved by default are: - -- The entry point (by default ``_start``). -- Any symbol which is to be exported. -- Any symbol transitively referenced by the above. - -Weak Undefined Functions -~~~~~~~~~~~~~~~~~~~~~~~~ - -On native platforms, calls to weak undefined functions end up as calls to the -null function pointer. With WebAssembly, direct calls must reference a defined -function (with the correct signature). In order to handle this case the linker -will generate function a stub containing only the ``unreachable`` instruction -and use this for any direct references to an undefined weak function. - -For example a runtime call to a weak undefined function ``foo`` will up trapping -on ``unreachable`` inside and linker-generated function called -``undefined:foo``. - -Missing features ----------------- - -- Merging of data section similar to ``SHF_MERGE`` in the ELF world is not - supported. -- No support for creating shared libraries. The spec for shared libraries in - WebAssembly is still in flux: - https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md - -.. _linking: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md diff --git a/lld/docs/_static/favicon.ico b/lld/docs/_static/favicon.ico deleted file mode 100644 index 724ad6e12d..0000000000 Binary files a/lld/docs/_static/favicon.ico and /dev/null differ diff --git a/lld/docs/_templates/indexsidebar.html b/lld/docs/_templates/indexsidebar.html deleted file mode 100644 index 588be9309b..0000000000 --- a/lld/docs/_templates/indexsidebar.html +++ /dev/null @@ -1,4 +0,0 @@ -

Bugs

- -

lld bugs should be reported at the - LLVM Bugzilla.

diff --git a/lld/docs/_templates/layout.html b/lld/docs/_templates/layout.html deleted file mode 100644 index 519a24bce6..0000000000 --- a/lld/docs/_templates/layout.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "!layout.html" %} - -{% block extrahead %} - -{% endblock %} - -{% block rootrellink %} -
  • lld Home | 
  • -{% endblock %} diff --git a/lld/docs/conf.py b/lld/docs/conf.py deleted file mode 100644 index 2df1aa7081..0000000000 --- a/lld/docs/conf.py +++ /dev/null @@ -1,255 +0,0 @@ -# -*- coding: utf-8 -*- -# -# lld documentation build configuration file. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os -from datetime import date - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'lld' -copyright = u'2011-%d, LLVM Project' % date.today().year - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short version. -version = '13' -# The full version, including alpha/beta/rc tags. -release = '13' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -today_fmt = '%Y-%m-%d' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -show_authors = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'friendly' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'llvm-theme' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ["."] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# If given, this must be the name of an image file (path relative to the -# configuration directory) that is the favicon of the docs. Modern browsers use -# this as icon for tabs, windows and bookmarks. It should be a Windows-style -# icon file (.ico), which is 16x16 or 32x32 pixels large. Default: None. The -# image file will be copied to the _static directory of the output HTML, but -# only if the file does not already exist there. -html_favicon = '_static/favicon.ico' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%Y-%m-%d' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -html_sidebars = {'index': ['indexsidebar.html']} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {'index': 'index.html'} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'llddoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('contents', 'lld.tex', u'lld Documentation', - u'LLVM project', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('contents', 'lld', u'lld Documentation', - [u'LLVM project'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('contents', 'lld', u'lld Documentation', - u'LLVM project', 'lld', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - - -# FIXME: Define intersphinx configuration. -intersphinx_mapping = {} - - -# -- Options for extensions ---------------------------------------------------- - -# Enable this if you want TODOs to show up in the generated documentation. -todo_include_todos = True diff --git a/lld/docs/design.rst b/lld/docs/design.rst deleted file mode 100644 index 20d8fe78a6..0000000000 --- a/lld/docs/design.rst +++ /dev/null @@ -1,421 +0,0 @@ -.. _design: - -Linker Design -============= - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -Introduction ------------- - -lld is a new generation of linker. It is not "section" based like traditional -linkers which mostly just interlace sections from multiple object files into the -output file. Instead, lld is based on "Atoms". Traditional section based -linking work well for simple linking, but their model makes advanced linking -features difficult to implement. Features like dead code stripping, reordering -functions for locality, and C++ coalescing require the linker to work at a finer -grain. - -An atom is an indivisible chunk of code or data. An atom has a set of -attributes, such as: name, scope, content-type, alignment, etc. An atom also -has a list of References. A Reference contains: a kind, an optional offset, an -optional addend, and an optional target atom. - -The Atom model allows the linker to use standard graph theory models for linking -data structures. Each atom is a node, and each Reference is an edge. The -feature of dead code stripping is implemented by following edges to mark all -live atoms, and then delete the non-live atoms. - - -Atom Model ----------- - -An atom is an indivisible chunk of code or data. Typically each user written -function or global variable is an atom. In addition, the compiler may emit -other atoms, such as for literal c-strings or floating point constants, or for -runtime data structures like dwarf unwind info or pointers to initializers. - -A simple "hello world" object file would be modeled like this: - -.. image:: hello.png - -There are three atoms: main, a proxy for printf, and an anonymous atom -containing the c-string literal "hello world". The Atom "main" has two -references. One is the call site for the call to printf, and the other is a -reference for the instruction that loads the address of the c-string literal. - -There are only four different types of atoms: - - * DefinedAtom - 95% of all atoms. This is a chunk of code or data - - * UndefinedAtom - This is a place holder in object files for a reference to some atom - outside the translation unit.During core linking it is usually replaced - by (coalesced into) another Atom. - - * SharedLibraryAtom - If a required symbol name turns out to be defined in a dynamic shared - library (and not some object file). A SharedLibraryAtom is the - placeholder Atom used to represent that fact. - - It is similar to an UndefinedAtom, but it also tracks information - about the associated shared library. - - * AbsoluteAtom - This is for embedded support where some stuff is implemented in ROM at - some fixed address. This atom has no content. It is just an address - that the Writer needs to fix up any references to point to. - - -File Model ----------- - -The linker views the input files as basically containers of Atoms and -References, and just a few attributes of their own. The linker works with three -kinds of files: object files, static libraries, and dynamic shared libraries. -Each kind of file has reader object which presents the file in the model -expected by the linker. - -Object File -~~~~~~~~~~~ - -An object file is just a container of atoms. When linking an object file, a -reader is instantiated which parses the object file and instantiates a set of -atoms representing all content in the .o file. The linker adds all those atoms -to a master graph. - -Static Library (Archive) -~~~~~~~~~~~~~~~~~~~~~~~~ - -This is the traditional unix static archive which is just a collection of object -files with a "table of contents". When linking with a static library, by default -nothing is added to the master graph of atoms. Instead, if after merging all -atoms from object files into a master graph, if any "undefined" atoms are left -remaining in the master graph, the linker reads the table of contents for each -static library to see if any have the needed definitions. If so, the set of -atoms from the specified object file in the static library is added to the -master graph of atoms. - -Dynamic Library (Shared Object) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Dynamic libraries are different than object files and static libraries in that -they don't directly add any content. Their purpose is to check at build time -that the remaining undefined references can be resolved at runtime, and provide -a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. The way -this is modeled in the linker is that a dynamic library contributes no atoms to -the initial graph of atoms. Instead, (like static libraries) if there are -"undefined" atoms in the master graph of all atoms, then each dynamic library is -checked to see if exports the required symbol. If so, a "shared library" atom is -instantiated by the by the reader which the linker uses to replace the -"undefined" atom. - -Linking Steps -------------- - -Through the use of abstract Atoms, the core of linking is architecture -independent and file format independent. All command line parsing is factored -out into a separate "options" abstraction which enables the linker to be driven -with different command line sets. - -The overall steps in linking are: - - #. Command line processing - - #. Parsing input files - - #. Resolving - - #. Passes/Optimizations - - #. Generate output file - -The Resolving and Passes steps are done purely on the master graph of atoms, so -they have no notion of file formats such as mach-o or ELF. - - -Input Files -~~~~~~~~~~~ - -Existing developer tools using different file formats for object files. -A goal of lld is to be file format independent. This is done -through a plug-in model for reading object files. The lld::Reader is the base -class for all object file readers. A Reader follows the factory method pattern. -A Reader instantiates an lld::File object (which is a graph of Atoms) from a -given object file (on disk or in-memory). - -Every Reader subclass defines its own "options" class (for instance the mach-o -Reader defines the class ReaderOptionsMachO). This options class is the -one-and-only way to control how the Reader operates when parsing an input file -into an Atom graph. For instance, you may want the Reader to only accept -certain architectures. The options class can be instantiated from command -line options, or it can be subclassed and the ivars programmatically set. - -Resolving -~~~~~~~~~ - -The resolving step takes all the atoms' graphs from each object file and -combines them into one master object graph. Unfortunately, it is not as simple -as appending the atom list from each file into one big list. There are many -cases where atoms need to be coalesced. That is, two or more atoms need to be -coalesced into one atom. This is necessary to support: C language "tentative -definitions", C++ weak symbols for templates and inlines defined in headers, -replacing undefined atoms with actual definition atoms, and for merging copies -of constants like c-strings and floating point constants. - -The linker support coalescing by-name and by-content. By-name is used for -tentative definitions and weak symbols. By-content is used for constant data -that can be merged. - -The resolving process maintains some global linking "state", including a "symbol -table" which is a map from llvm::StringRef to lld::Atom*. With these data -structures, the linker iterates all atoms in all input files. For each atom, it -checks if the atom is named and has a global or hidden scope. If so, the atom -is added to the symbol table map. If there already is a matching atom in that -table, that means the current atom needs to be coalesced with the found atom, or -it is a multiple definition error. - -When all initial input file atoms have been processed by the resolver, a scan is -made to see if there are any undefined atoms in the graph. If there are, the -linker scans all libraries (both static and dynamic) looking for definitions to -replace the undefined atoms. It is an error if any undefined atoms are left -remaining. - -Dead code stripping (if requested) is done at the end of resolving. The linker -does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main -executable) and follows each references and marks each Atom that it visits as -"live". When done, all atoms not marked "live" are removed. - -The result of the Resolving phase is the creation of an lld::File object. The -goal is that the lld::File model is **the** internal representation -throughout the linker. The file readers parse (mach-o, ELF, COFF) into an -lld::File. The file writers (mach-o, ELF, COFF) taken an lld::File and produce -their file kind, and every Pass only operates on an lld::File. This is not only -a simpler, consistent model, but it enables the state of the linker to be dumped -at any point in the link for testing purposes. - - -Passes -~~~~~~ - -The Passes step is an open ended set of routines that each get a change to -modify or enhance the current lld::File object. Some example Passes are: - - * stub (PLT) generation - - * GOT instantiation - - * order_file optimization - - * branch island generation - - * branch shim generation - - * Objective-C optimizations (Darwin specific) - - * TLV instantiation (Darwin specific) - - * DTrace probe processing (Darwin specific) - - * compact unwind encoding (Darwin specific) - - -Some of these passes are specific to Darwin's runtime environments. But many of -the passes are applicable to any OS (such as generating branch island for out of -range branch instructions). - -The general structure of a pass is to iterate through the atoms in the current -lld::File object, inspecting each atom and doing something. For instance, the -stub pass, looks for call sites to shared library atoms (e.g. call to printf). -It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for -each proxy atom needed, and these new atoms are added to the current lld::File -object. Next, all the noted call sites to shared library atoms have their -References altered to point to the stub atom instead of the shared library atom. - - -Generate Output File -~~~~~~~~~~~~~~~~~~~~ - -Once the passes are done, the output file writer is given current lld::File -object. The writer's job is to create the executable content file wrapper and -place the content of the atoms into it. - -lld uses a plug-in model for writing output files. All concrete writers (e.g. -ELF, mach-o, etc) are subclasses of the lld::Writer class. - -Unlike the Reader class which has just one method to instantiate an lld::File, -the Writer class has multiple methods. The crucial method is to generate the -output file, but there are also methods which allow the Writer to contribute -Atoms to the resolver and specify passes to run. - -An example of contributing -atoms is that if the Writer knows a main executable is being linked and such -an executable requires a specially named entry point (e.g. "_main"), the Writer -can add an UndefinedAtom with that special name to the resolver. This will -cause the resolver to issue an error if that symbol is not defined. - -Sometimes a Writer supports lazily created symbols, such as names for the start -of sections. To support this, the Writer can create a File object which vends -no initial atoms, but does lazily supply atoms by name as needed. - -Every Writer subclass defines its own "options" class (for instance the mach-o -Writer defines the class WriterOptionsMachO). This options class is the -one-and-only way to control how the Writer operates when producing an output -file from an Atom graph. For instance, you may want the Writer to optimize -the output for certain OS versions, or strip local symbols, etc. The options -class can be instantiated from command line options, or it can be subclassed -and the ivars programmatically set. - - -lld::File representations -------------------------- - -Just as LLVM has three representations of its IR model, lld has two -representations of its File/Atom/Reference model: - - * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File). - - * textual (in YAML) - - -Textual representations in YAML -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In designing a textual format we want something easy for humans to read and easy -for the linker to parse. Since an atom has lots of attributes most of which are -usually just the default, we should define default values for every attribute so -that those can be omitted from the text representation. Here is the atoms for a -simple hello world program expressed in YAML:: - - target-triple: x86_64-apple-darwin11 - - atoms: - - name: _main - scope: global - type: code - content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00, - 00, 00, 31, c0, 5d, c3 ] - fixups: - - offset: 07 - kind: pcrel32 - target: 2 - - offset: 0E - kind: call32 - target: _fprintf - - - type: c-string - content: [ 73, 5A, 00 ] - - ... - -The biggest use for the textual format will be writing test cases. Writing test -cases in C is problematic because the compiler may vary its output over time for -its own optimization reasons which my inadvertently disable or break the linker -feature trying to be tested. By writing test cases in the linkers own textual -format, we can exactly specify every attribute of every atom and thus target -specific linker logic. - -The textual/YAML format follows the ReaderWriter patterns used in lld. The lld -library comes with the classes: ReaderYAML and WriterYAML. - - -Testing -------- - -The lld project contains a test suite which is being built up as new code is -added to lld. All new lld functionality should have a tests added to the test -suite. The test suite is `lit `_ driven. Each -test is a text file with comments telling lit how to run the test and check the -result To facilitate testing, the lld project builds a tool called lld-core. -This tool reads a YAML file (default from stdin), parses it into one or more -lld::File objects in memory and then feeds those lld::File objects to the -resolver phase. - - -Resolver testing -~~~~~~~~~~~~~~~~ - -Basic testing is the "core linking" or resolving phase. That is where the -linker merges object files. All test cases are written in YAML. One feature of -YAML is that it allows multiple "documents" to be encoding in one YAML stream. -That means one text file can appear to the linker as multiple .o files - the -normal case for the linker. - -Here is a simple example of a core linking test case. It checks that an -undefined atom from one file will be replaced by a definition from another -file:: - - # RUN: lld-core %s | FileCheck %s - - # - # Test that undefined atoms are replaced with defined atoms. - # - - --- - atoms: - - name: foo - definition: undefined - --- - atoms: - - name: foo - scope: global - type: code - ... - - # CHECK: name: foo - # CHECK: scope: global - # CHECK: type: code - # CHECK-NOT: name: foo - # CHECK: ... - - -Passes testing -~~~~~~~~~~~~~~ - -Since Passes just operate on an lld::File object, the lld-core tool has the -option to run a particular pass (after resolving). Thus, you can write a YAML -test case with carefully crafted input to exercise areas of a Pass and the check -the resulting lld::File object as represented in YAML. - - -Design Issues -------------- - -There are a number of open issues in the design of lld. The plan is to wait and -make these design decisions when we need to. - - -Debug Info -~~~~~~~~~~ - -Currently, the lld model says nothing about debug info. But the most popular -debug format is DWARF and there is some impedance mismatch with the lld model -and DWARF. In lld there are just Atoms and only Atoms that need to be in a -special section at runtime have an associated section. Also, Atoms do not have -addresses. The way DWARF is spec'ed different parts of DWARF are supposed to go -into specially named sections and the DWARF references function code by address. - -CPU and OS specific functionality -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Currently, lld has an abstract "Platform" that deals with any CPU or OS specific -differences in linking. We just keep adding virtual methods to the base -Platform class as we find linking areas that might need customization. At some -point we'll need to structure this better. - - -File Attributes -~~~~~~~~~~~~~~~ - -Currently, lld::File just has a path and a way to iterate its atoms. We will -need to add more attributes on a File. For example, some equivalent to the -target triple. There is also a number of cached or computed attributes that -could make various Passes more efficient. For instance, on Darwin there are a -number of Objective-C optimizations that can be done by a Pass. But it would -improve the plain C case if the Objective-C optimization Pass did not have to -scan all atoms looking for any Objective-C data structures. This could be done -if the lld::File object had an attribute that said if the file had any -Objective-C data in it. The Resolving phase would then be required to "merge" -that attribute as object files are added. diff --git a/lld/docs/development.rst b/lld/docs/development.rst deleted file mode 100644 index 81b826f648..0000000000 --- a/lld/docs/development.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _development: - -Development -=========== - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -lld is developed as part of the `LLVM `_ project. - -Creating a Reader ------------------ - -See the :ref:`Creating a Reader ` guide. - - -Modifying the Driver --------------------- - -See :doc:`Driver`. - - -Debugging ---------- - -You can run lld with ``-mllvm -debug`` command line options to enable debugging -printouts. If you want to enable debug information for some specific pass, you -can run it with ``-mllvm '-debug-only='``, where pass is a name used in -the ``DEBUG_WITH_TYPE()`` macro. - - - -Documentation -------------- - -The project documentation is written in reStructuredText and generated using the -`Sphinx `_ documentation generator. For more -information on writing documentation for the project, see the -:ref:`sphinx_intro`. - -.. toctree:: - :hidden: - - Readers - Driver diff --git a/lld/docs/error_handling_script.rst b/lld/docs/error_handling_script.rst deleted file mode 100644 index 53efa8b7a3..0000000000 --- a/lld/docs/error_handling_script.rst +++ /dev/null @@ -1,39 +0,0 @@ -===================== -Error Handling Script -===================== - -LLD provides the ability to hook into some error handling routines through a -user-provided script specified with ``--error-handling-script=`` -when certain errors are encountered. This document specifies the requirements of -such a script. - -Generic Requirements -==================== - -The script is expected to be available in the ``PATH`` or to be provided using a -full path. It must be executable. It is executed in the same environment as the -parent process. - -Arguments -========= - -LLD calls the error handling script using the following arguments:: - - error-handling-script - -The following tags are supported: - -- ``missing-lib``: indicates that LLD failed to find a library. The library name - is specified as the second argument, e.g. ``error-handling-script missing-lib - mylib`` - -- ``undefined-symbol``: indicates that given symbol is marked as undefined. The - unmangled symbol name is specified as the second argument, e.g. - ``error-handling-script undefined-symbol mysymbol`` - -Return Value -============ - -Upon success, the script is expected to return 0. A non-zero value is -interpreted as an error and reported to the user. In both cases, LLD still -reports the original error. diff --git a/lld/docs/getting_started.rst b/lld/docs/getting_started.rst deleted file mode 100644 index 506cb24dde..0000000000 --- a/lld/docs/getting_started.rst +++ /dev/null @@ -1,87 +0,0 @@ -.. _getting_started: - -Getting Started: Building and Running lld -========================================= - -This page gives you the shortest path to checking out and building lld. If you -run into problems, please file bugs in the `LLVM Bugzilla`__ - -__ https://bugs.llvm.org/ - -Building lld ------------- - -On Unix-like Systems -~~~~~~~~~~~~~~~~~~~~ - -1. Get the required tools. - - * `CMake 2.8`_\+. - * make (or any build system CMake supports). - * `Clang 3.1`_\+ or GCC 4.7+ (C++11 support is required). - - * If using Clang, you will also need `libc++`_. - * `Python 2.4`_\+ (not 3.x) for running tests. - -.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html -.. _Clang 3.1: http://clang.llvm.org/ -.. _libc++: http://libcxx.llvm.org/ -.. _Python 2.4: http://python.org/download/ - -2. Check out LLVM and subprojects (including lld):: - - $ git clone https://github.com/llvm/llvm-project.git - -4. Build LLVM and lld:: - - $ cd llvm-project - $ mkdir build && cd build - $ cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS=lld ../llvm - $ make - - * If you want to build with clang and it is not the default compiler or - it is installed in an alternate location, you'll need to tell the cmake tool - the location of the C and C++ compiler via CMAKE_C_COMPILER and - CMAKE_CXX_COMPILER. For example:: - - $ cmake -DCMAKE_CXX_COMPILER=/path/to/clang++ -DCMAKE_C_COMPILER=/path/to/clang ... - -5. Test:: - - $ make check-lld - -Using Visual Studio -~~~~~~~~~~~~~~~~~~~ - -#. Get the required tools. - - * `CMake 2.8`_\+. - * `Visual Studio 12 (2013) or later`_ (required for C++11 support) - * `Python 2.4`_\+ (not 3.x) for running tests. - -.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html -.. _Visual Studio 12 (2013) or later: http://www.microsoft.com/visualstudio/11/en-us -.. _Python 2.4: http://python.org/download/ - -#. Check out LLVM as above. - -#. Generate Visual Studio project files:: - - $ cd llvm-project/build (out of source build required) - $ cmake -G "Visual Studio 11" -DLLVM_ENABLE_PROJECTS=lld ../llvm - -#. Build - - * Open LLVM.sln in Visual Studio. - * Build the ``ALL_BUILD`` target. - -#. Test - - * Build the ``lld-test`` target. - -More Information -~~~~~~~~~~~~~~~~ - -For more information on using CMake see the `LLVM CMake guide`_. - -.. _LLVM CMake guide: https://llvm.org/docs/CMake.html diff --git a/lld/docs/hello.png b/lld/docs/hello.png deleted file mode 100644 index 70df111f1a..0000000000 Binary files a/lld/docs/hello.png and /dev/null differ diff --git a/lld/docs/index.rst b/lld/docs/index.rst deleted file mode 100644 index b0080f54df..0000000000 --- a/lld/docs/index.rst +++ /dev/null @@ -1,182 +0,0 @@ -LLD - The LLVM Linker -===================== - -LLD is a linker from the LLVM project that is a drop-in replacement -for system linkers and runs much faster than them. It also provides -features that are useful for toolchain developers. - -The linker supports ELF (Unix), PE/COFF (Windows), Mach-O (macOS) and -WebAssembly in descending order of completeness. Internally, LLD consists of -several different linkers. The ELF port is the one that will be described in -this document. The PE/COFF port is complete, including -Windows debug info (PDB) support. The WebAssembly port is still a work in -progress (See :doc:`WebAssembly`). The Mach-O port is built based on a -different architecture than the others. For the details about Mach-O, please -read :doc:`AtomLLD`. - -Features --------- - -- LLD is a drop-in replacement for the GNU linkers that accepts the - same command line arguments and linker scripts as GNU. - - We are currently working closely with the FreeBSD project to make - LLD default system linker in future versions of the operating - system, so we are serious about addressing compatibility issues. As - of February 2017, LLD is able to link the entire FreeBSD/amd64 base - system including the kernel. With a few work-in-progress patches it - can link approximately 95% of the ports collection on AMD64. For the - details, see `FreeBSD quarterly status report - `_. - -- LLD is very fast. When you link a large program on a multicore - machine, you can expect that LLD runs more than twice as fast as the GNU - gold linker. Your mileage may vary, though. - -- It supports various CPUs/ABIs including AArch64, AMDGPU, ARM, Hexagon, MIPS - 32/64 big/little-endian, PowerPC, PowerPC64, RISC-V, SPARC V9, x86-32 and - x86-64. Among these, AArch64, ARM (>= v6), PowerPC, PowerPC64, x86-32 and - x86-64 have production quality. MIPS seems decent too. - -- It is always a cross-linker, meaning that it always supports all the - above targets however it was built. In fact, we don't provide a - build-time option to enable/disable each target. This should make it - easy to use our linker as part of a cross-compile toolchain. - -- You can embed LLD in your program to eliminate dependencies on - external linkers. All you have to do is to construct object files - and command line arguments just like you would do to invoke an - external linker and then call the linker's main function, - ``lld::elf::link``, from your code. - -- It is small. We are using LLVM libObject library to read from object - files, so it is not a completely fair comparison, but as of February - 2017, LLD/ELF consists only of 21k lines of C++ code while GNU gold - consists of 198k lines of C++ code. - -- Link-time optimization (LTO) is supported by default. Essentially, - all you have to do to do LTO is to pass the ``-flto`` option to clang. - Then clang creates object files not in the native object file format - but in LLVM bitcode format. LLD reads bitcode object files, compile - them using LLVM and emit an output file. Because in this way LLD can - see the entire program, it can do the whole program optimization. - -- Some very old features for ancient Unix systems (pre-90s or even - before that) have been removed. Some default settings have been - tuned for the 21st century. For example, the stack is marked as - non-executable by default to tighten security. - -Performance ------------ - -This is a link time comparison on a 2-socket 20-core 40-thread Xeon -E5-2680 2.80 GHz machine with an SSD drive. We ran gold and lld with -or without multi-threading support. To disable multi-threading, we -added ``-no-threads`` to the command lines. - -============ =========== ============ ==================== ================== =============== ============= -Program Output size GNU ld GNU gold w/o threads GNU gold w/threads lld w/o threads lld w/threads -ffmpeg dbg 92 MiB 1.72s 1.16s 1.01s 0.60s 0.35s -mysqld dbg 154 MiB 8.50s 2.96s 2.68s 1.06s 0.68s -clang dbg 1.67 GiB 104.03s 34.18s 23.49s 14.82s 5.28s -chromium dbg 1.14 GiB 209.05s [1]_ 64.70s 60.82s 27.60s 16.70s -============ =========== ============ ==================== ================== =============== ============= - -As you can see, lld is significantly faster than GNU linkers. -Note that this is just a benchmark result of our environment. -Depending on number of available cores, available amount of memory or -disk latency/throughput, your results may vary. - -.. [1] Since GNU ld doesn't support the ``-icf=all`` and - ``-gdb-index`` options, we removed them from the command line - for GNU ld. GNU ld would have been slower than this if it had - these options. - -Build ------ - -If you have already checked out LLVM using SVN, you can check out LLD -under ``tools`` directory just like you probably did for clang. For the -details, see `Getting Started with the LLVM System -`_. - -If you haven't checked out LLVM, the easiest way to build LLD is to -check out the entire LLVM projects/sub-projects from a git mirror and -build that tree. You need `cmake` and of course a C++ compiler. - -.. code-block:: console - - $ git clone https://github.com/llvm/llvm-project llvm-project - $ mkdir build - $ cd build - $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local ../llvm-project/llvm - $ make install - -Using LLD ---------- - -LLD is installed as ``ld.lld``. On Unix, linkers are invoked by -compiler drivers, so you are not expected to use that command -directly. There are a few ways to tell compiler drivers to use ld.lld -instead of the default linker. - -The easiest way to do that is to overwrite the default linker. After -installing LLD to somewhere on your disk, you can create a symbolic -link by doing ``ln -s /path/to/ld.lld /usr/bin/ld`` so that -``/usr/bin/ld`` is resolved to LLD. - -If you don't want to change the system setting, you can use clang's -``-fuse-ld`` option. In this way, you want to set ``-fuse-ld=lld`` to -LDFLAGS when building your programs. - -LLD leaves its name and version number to a ``.comment`` section in an -output. If you are in doubt whether you are successfully using LLD or -not, run ``readelf --string-dump .comment `` and examine the -output. If the string "Linker: LLD" is included in the output, you are -using LLD. - -History -------- - -Here is a brief project history of the ELF and COFF ports. - -- May 2015: We decided to rewrite the COFF linker and did that. - Noticed that the new linker is much faster than the MSVC linker. - -- July 2015: The new ELF port was developed based on the COFF linker - architecture. - -- September 2015: The first patches to support MIPS and AArch64 landed. - -- October 2015: Succeeded to self-host the ELF port. We have noticed - that the linker was faster than the GNU linkers, but we weren't sure - at the time if we would be able to keep the gap as we would add more - features to the linker. - -- July 2016: Started working on improving the linker script support. - -- December 2016: Succeeded to build the entire FreeBSD base system - including the kernel. We had widen the performance gap against the - GNU linkers. - -Internals ---------- - -For the internals of the linker, please read :doc:`NewLLD`. It is a bit -outdated but the fundamental concepts remain valid. We'll update the -document soon. - -.. toctree:: - :maxdepth: 1 - - NewLLD - AtomLLD - WebAssembly - windows_support - missingkeyfunction - error_handling_script - Partitions - ReleaseNotes - ELF/linker_script - ELF/start-stop-gc - ELF/warn_backrefs diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 deleted file mode 100644 index bd67e58daa..0000000000 --- a/lld/docs/ld.lld.1 +++ /dev/null @@ -1,881 +0,0 @@ -.\" Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -.\" See https://llvm.org/LICENSE.txt for license information. -.\" SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -.\" -.\" This man page documents only lld's ELF linking support, obtained originally -.\" from FreeBSD. -.Dd May 12, 2019 -.Dt LD.LLD 1 -.Os -.Sh NAME -.Nm ld.lld -.Nd ELF linker from the LLVM project -.Sh SYNOPSIS -.Nm ld.lld -.Op Ar options -.Ar objfile ... -.Sh DESCRIPTION -A linker takes one or more object, archive, and library files, and combines -them into an output file (an executable, a shared library, or another object -file). -It relocates code and data from the input files and resolves symbol -references between them. -.Pp -.Nm -is a drop-in replacement for the GNU BFD and gold linkers. -It accepts most of the same command line arguments and linker scripts -as GNU linkers. -.Pp -.Nm -currently supports i386, x86-64, ARM, AArch64, PowerPC32, PowerPC64, -MIPS32, MIPS64, RISC-V, AMDGPU, Hexagon and SPARC V9 targets. -.Nm -acts as a Microsoft link.exe-compatible linker if invoked as -.Nm lld-link -and as macOS's ld if invoked as -.Nm ld.ld64. -All these targets are always supported however -.Nm -was built, so you can always use -.Nm -as a native linker as well as a cross linker. -.Sh OPTIONS -Many options have both a single-letter and long form. -When using the long form options other than those beginning with the -letter -.Cm o -may be specified using either one or two dashes preceding the option name. -Long options beginning with -.Cm o -require two dashes to avoid confusion with the -.Fl o Ar path -option. -.Pp -.Bl -tag -width indent -.It Fl -allow-multiple-definition -Do not error if a symbol is defined multiple times. -The first definition will be used. -.It Fl -allow-shlib-undefined -Allow unresolved references in shared libraries. -This option is enabled by default when linking a shared library. -.It Fl -apply-dynamic-relocs -Apply link-time values for dynamic relocations. -.It Fl -as-needed -Only set -.Dv DT_NEEDED -for shared libraries if used. -.It Fl -auxiliary Ns = Ns Ar value -Set the -.Dv DT_AUXILIARY -field to the specified name. -.It Fl -Bdynamic , Fl -dy -Link against shared libraries. -.It Fl -Bstatic , Fl -static , Fl -dn -Do not link against shared libraries. -.It Fl Bno-symbolic -Don't bind default visibility defined symbols locally for -.Fl shared -(default). -.It Fl Bsymbolic -Bind default visibility defined symbols locally for -.Fl shared. -Also set the -.Dv DF_SYMBOLIC -flag. -.It Fl Bsymbolic-functions -Bind default visibility defined function symbols locally for -.Fl shared. -.It Fl Bsymbolic-non-weak-functions -Bind default visibility defined STB_GLOBAL function symbols locally for -.Fl shared. -.It Fl -build-id Ns = Ns Ar value -Generate a build ID note. -.Ar value -may be one of -.Cm fast , -.Cm md5 , -.Cm sha1 , -.Cm tree , -.Cm uuid , -.Cm 0x Ns Ar hex-string , -and -.Cm none . -.Cm tree -is an alias for -.Cm sha1 . -Build-IDs of type -.Cm fast , -.Cm md5 , -.Cm sha1 , -and -.Cm tree -are calculated from the object contents. -.Cm fast -is not intended to be cryptographically secure. -.It Fl -build-id -Synonym for -.Fl -build-id Ns = Ns Cm fast . -.It Fl -color-diagnostics Ns = Ns Ar value -Use colors in diagnostics. -.Ar value -may be one of -.Cm always , -.Cm auto , -and -.Cm never . -.Cm auto -enables color if and only if output is to a terminal. -.It Fl -color-diagnostics -Alias for -.Fl -color-diagnostics Ns = Ns Cm auto . -.It Fl -compress-debug-sections Ns = Ns Ar value -Compress DWARF debug sections. -.Ar value -may be -.Cm none -or -.Cm zlib . -The default compression level is 1 (fastest) as the debug info usually -compresses well at that level, but if you want to compress it more, -you can specify -.Fl O2 -to set the compression level to 6. -.It Fl -cref -Output cross reference table. -.It Fl -define-common , Fl d -Assign space to common symbols. -.It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression -Define a symbol alias. -.Ar expression -may be another symbol or a linker script expression. -For example, -.Ql --defsym=foo=bar -or -.Ql --defsym=foo=bar+0x100 . -.It Fl -demangle -Demangle symbol names. -.It Fl -disable-new-dtags -Disable new dynamic tags. -.It Fl -discard-all , Fl x -Delete all local symbols. -.It Fl -discard-locals , Fl X -Delete temporary local symbols. -.It Fl -discard-none -Keep all symbols in the symbol table. -.It Fl -dynamic-linker Ns = Ns Ar value -Specify the dynamic linker to be used for a dynamically linked executable. -This is recorded in an ELF segment of type -.Dv PT_INTERP . -.It Fl -dynamic-list Ns = Ns Ar file -Read a list of dynamic symbols from -.Ar file . -(executable) Put matched non-local defined symbols to the dynamic symbol table. -(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object. Implies -.Cm -Bsymbolic -but does not set DF_SYMBOLIC -.It Fl -EB -Select the big-endian format in the OUTPUT_FORMAT command. -.It Fl -EL -Select the little-endian format in the OUTPUT_FORMAT command. -.It Fl -eh-frame-hdr -Request creation of -.Li .eh_frame_hdr -section and -.Dv PT_GNU_EH_FRAME -segment header. -.It Fl -emit-relocs , Fl q -Generate relocations in the output. -.It Fl -enable-new-dtags -Enable new dynamic tags. -.It Fl -end-lib -End a grouping of objects that should be treated as if they were together -in an archive. -.It Fl -entry Ns = Ns Ar entry -Name of entry point symbol. -.It Fl -error-limit Ns = Ns Ar value -Maximum number of errors to emit before stopping. -A value of zero indicates that there is no limit. -.It Fl -error-unresolved-symbols -Report unresolved symbols as errors. -.It Fl -error-handing-script Ns = Ns Ar script_path -Call script -.Ar script_path -upon some error, with -.Ar tag -as first argument, and an extra parameter as second argument. The script is -expected to return 0 on success. Any other value is considered a generic error. -.Ar tag -may be -.Cm missing-lib -followed by the name of the missing library. -.Cm undefined-symbol -followed by the name of the undefined symbol. -.It Fl -execute-only -Mark executable sections unreadable. -This option is currently only supported on AArch64. -.It Fl -exclude-libs Ns = Ns Ar value -Exclude static libraries from automatic export. -.It Fl -export-dynamic , Fl E -Put symbols in the dynamic symbol table. -.It Fl -export-dynamic-symbol Ns = Ns Ar glob -(executable) Put matched non-local defined symbols to the dynamic symbol table. -(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object even if they would otherwise be due to -.Cm -Bsymbolic -, -.Cm -Bsymbolic-functions -or -.Cm --dynamic-list -.It Fl -fatal-warnings -Treat warnings as errors. -.It Fl -filter Ns = Ns Ar value , Fl F Ar value -Set the -.Dv DT_FILTER -field to the specified value. -.It Fl -fini Ns = Ns Ar symbol -Specify a finalizer function. -.It Fl -format Ns = Ns Ar input-format , Fl b Ar input-format -Specify the format of the inputs following this option. -.Ar input-format -may be one of -.Cm binary , -.Cm elf , -and -.Cm default . -.Cm default -is a synonym for -.Cm elf . -.It Fl -gc-sections -Enable garbage collection of unused sections. -.It Fl -gdb-index -Generate -.Li .gdb_index -section. -.It Fl -hash-style Ns = Ns Ar value -Specify hash style. -.Ar value -may be -.Cm sysv , -.Cm gnu , -or -.Cm both . -.Cm both -is the default. -.It Fl -help -Print a help message. -.It Fl -icf Ns = Ns Cm all -Enable identical code folding. -.It Fl -icf Ns = Ns Cm safe -Enable safe identical code folding. -.It Fl -icf Ns = Ns Cm none -Disable identical code folding. -.It Fl -ignore-data-address-equality -Ignore address equality of data. C/C++ requires each data to have a unique -address. -This option allows lld to do unsafe optimization that breaks the -requirement: create copies of read-only data or merge two or more read-only data -that happen to have the same value. -.It Fl -ignore-function-address-equality -Ignore address equality of functions. -This option allows non-PIC calls to a function with non-default visibility in -a shared object. -The function may have different addresses within the executable and within the -shared object. -.It Fl -image-base Ns = Ns Ar value -Set the base address to -.Ar value . -.It Fl -init Ns = Ns Ar symbol -Specify an initializer function. -.It Fl -keep-unique Ns = Ns Ar symbol -Do not fold -.Ar symbol -during ICF. -.It Fl l Ar libName, Fl -library Ns = Ns Ar libName -Root name of library to use. -.It Fl L Ar dir , Fl -library-path Ns = Ns Ar dir -Add a directory to the library search path. -.It Fl -lto-aa-pipeline Ns = Ns Ar value -AA pipeline to run during LTO. -Used in conjunction with -.Fl -lto-newpm-passes . -.It Fl -lto-newpm-passes Ns = Ns Ar value -Passes to run during LTO. -.It Fl -lto-O Ns Ar opt-level -Optimization level for LTO. -.It Fl -lto-partitions Ns = Ns Ar value -Number of LTO codegen partitions. -.It Fl m Ar value -Set target emulation. -.It Fl -Map Ns = Ns Ar file , Fl M Ar file -Print a link map to -.Ar file . -.It Fl -nmagic , Fl n -Do not page align sections, link against static libraries. -.It Fl -no-allow-shlib-undefined -Do not allow unresolved references in shared libraries. -This option is enabled by default when linking an executable. -.It Fl -no-as-needed -Always set -.Dv DT_NEEDED -for shared libraries. -.It Fl -no-color-diagnostics -Do not use colors in diagnostics. -.It Fl -no-define-common -Do not assign space to common symbols. -.It Fl -no-demangle -Do not demangle symbol names. -.It Fl -no-dynamic-linker -Inhibit output of an -.Li .interp -section. -.It Fl -no-fortran-common -Do not search archive members for definitions to override COMMON symbols. -.It Fl -no-gc-sections -Disable garbage collection of unused sections. -.It Fl -no-gnu-unique -Disable STB_GNU_UNIQUE symbol binding. -.It Fl -no-merge-exidx-entries -Disable merging .ARM.exidx entries. -.It Fl -no-nmagic -Page align sections. -.It Fl -no-omagic -Do not set the text data sections to be writable, page align sections. -.It Fl -no-relax -Disable target-specific relaxations. This is currently a no-op. -.It Fl -no-rosegment -Do not put read-only non-executable sections in their own segment. -.It Fl -no-undefined-version -Report version scripts that refer undefined symbols. -.It Fl -no-undefined -Report unresolved symbols even if the linker is creating a shared library. -.It Fl -no-warn-symbol-ordering -Do not warn about problems with the symbol ordering file or call graph profile. -.It Fl -no-whole-archive -Restores the default behavior of loading archive members. -.It Fl -no-pie , Fl -no-pic-executable -Do not create a position independent executable. -.It Fl -noinhibit-exec -Retain the executable output file whenever it is still usable. -.It Fl -nostdlib -Only search directories specified on the command line. -.It Fl o Ar path -Write the output executable, library, or object to -.Ar path . -If not specified, -.Dv a.out -is used as a default. -.It Fl O Ns Ar value -Optimize output file size. -.Ar value -may be: -.Pp -.Bl -tag -width 2n -compact -.It Cm 0 -Disable string merging. -.It Cm 1 -Enable string merging. -.It Cm 2 -Enable string tail merging. If -.Fl -compress-debug-sections -is given, compress debug sections at compression level 6 instead of 1. -.El -.Pp -.Fl O Ns Cm 1 -is the default. -.It Fl -oformat Ns = Ns Ar format -Specify the format for the output object file. -The only supported -.Ar format -is -.Cm binary , -which produces output with no ELF header. -.It Fl -omagic , Fl N -Set the text and data sections to be readable and writable, do not page align -sections, link against static libraries. -.It Fl -opt-remarks-filename Ar file -Write optimization remarks in YAML format to -.Ar file . -.It Fl -opt-remarks-passes Ar pass-regex -Filter optimization remarks by only allowing the passes matching -.Ar pass-regex . -.It Fl -opt-remarks-with-hotness -Include hotness information in the optimization remarks file. -.It Fl -orphan-handling Ns = Ns Ar mode -Control how orphan sections are handled. -An orphan section is one not specifically mentioned in a linker script. -.Ar mode -may be: -.Pp -.Bl -tag -width 2n -compact -.It Cm place -Place orphan sections in suitable output sections. -.It Cm warn -Place orphan sections as for -.Cm place -and also report a warning. -.It Cm error -Place orphan sections as for -.Cm place -and also report an error. -.El -.Pp -.Cm place -is the default. -.It Fl -pack-dyn-relocs Ns = Ns Ar format -Pack dynamic relocations in the given format. -.Ar format -may be: -.Pp -.Bl -tag -width 2n -compact -.It Cm none -Do not pack. -Dynamic relocations are encoded in SHT_REL(A). -.It Cm android -Pack dynamic relocations in SHT_ANDROID_REL(A). -.It Cm relr -Pack relative relocations in SHT_RELR, and the rest of dynamic relocations in -SHT_REL(A). -.It Cm android+relr -Pack relative relocations in SHT_RELR, and the rest of dynamic relocations in -SHT_ANDROID_REL(A). -.El -.Pp -.Cm none -is the default. -If -.Fl -use-android-relr-tags -is specified, use SHT_ANDROID_RELR instead of SHT_RELR. -.Pp -.It Fl -pic-veneer -Always generate position independent thunks. -.It Fl -pie , Fl -pic-executable -Create a position independent executable. -.It Fl -print-gc-sections -List removed unused sections. -.It Fl -print-icf-sections -List identical folded sections. -.It Fl -print-map -Print a link map to the standard output. -.It Fl -print-archive-stats Ns = Ns Ar file -Write archive usage statistics to the specified file. -Print the numbers of members and fetched members for each archive. -.It Fl -push-state -Save the current state of -.Fl -as-needed , -.Fl -static , -and -.Fl -whole-archive. -.It Fl -pop-state -Undo the effect of -.Fl -push-state. -.It Fl -relocatable , Fl r -Create relocatable object file. -.It Fl -reproduce Ns = Ns Ar path -Write a tar file to -.Ar path, -containing all the input files needed to reproduce the link, a text file called -response.txt containing the command line options and a text file called -version.txt containing the output of ld.lld --version. -The archive when -unpacked can be used to re-run the linker with the same options and input files. -.It Fl -retain-symbols-file Ns = Ns Ar file -Retain only the symbols listed in the file. -.It Fl -rpath Ns = Ns Ar value , Fl R Ar value -Add a -.Dv DT_RUNPATH -to the output. -.It Fl -rsp-quoting Ns = Ns Ar value -Quoting style for response files. -The supported values are -.Cm windows -and -.Cm posix . -.It Fl -script Ns = Ns Ar file , Fl T Ar file -Read linker script from -.Ar file . -If multiple linker scripts are given, they are processed as if they -were concatenated in the order they appeared on the command line. -.It Fl -section-start Ns = Ns Ar section Ns = Ns Ar address -Set address of section. -.It Fl -shared , Fl -Bsharable -Build a shared object. -.It Fl -shuffle-sections Ns = Ns Ar seed -Shuffle matched sections using the given seed before mapping them to the output sections. -If -1, reverse the section order. If 0, use a random seed. -.It Fl -soname Ns = Ns Ar value , Fl h Ar value -Set -.Dv DT_SONAME -to -.Ar value . -.It Fl -sort-common -This option is ignored for GNU compatibility. -.It Fl -sort-section Ns = Ns Ar value -Specifies sections sorting rule when linkerscript is used. -.It Fl -start-lib -Start a grouping of objects that should be treated as if they were together -in an archive. -.It Fl -strip-all , Fl s -Strip all symbols. -Implies -.Fl -strip-debug . -.It Fl -strip-debug , Fl S -Strip debugging information. -.It Fl -symbol-ordering-file Ns = Ns Ar file -Lay out sections in the order specified by -.Ar file . -.It Fl -sysroot Ns = Ns Ar value -Set the system root. -.It Fl -target1-abs -Interpret -.Dv R_ARM_TARGET1 -as -.Dv R_ARM_ABS32 . -.It Fl -target1-rel -Interpret -.Dv R_ARM_TARGET1 -as -.Dv R_ARM_REL32 . -.It Fl -target2 Ns = Ns Ar type -Interpret -.Dv R_ARM_TARGET2 -as -.Ar type , -where -.Ar type -is one of -.Cm rel , -.Cm abs , -or -.Cm got-rel . -.It Fl -Tbss Ns = Ns Ar value -Same as -.Fl -section-start -with -.Li .bss -as the sectionname. -.It Fl -Tdata Ns = Ns Ar value -Same as -.Fl -section-start -with -.Li .data -as the sectionname. -.It Fl -Ttext Ns = Ns Ar value -Same as -.Fl -section-start -with -.Li .text -as the sectionname. -.It Fl -thinlto-cache-dir Ns = Ns Ar value -Path to ThinLTO cached object file directory. -.It Fl -thinlto-cache-policy Ns = Ns Ar value -Pruning policy for the ThinLTO cache. -.It Fl -thinlto-jobs Ns = Ns Ar value -Number of ThinLTO jobs. -.It Fl -threads Ns = Ns Ar N -Number of threads. -.Cm all -(default) means all of concurrent threads supported. -.Cm 1 -disables multi-threading. -.It Fl -time-trace -Record time trace. -.It Fl -time-trace-file Ns = Ns Ar file -Write time trace output to -.Ar file . -.It Fl -time-trace-granularity Ns = Ns Ar value -Minimum time granularity (in microseconds) traced by time profiler. -.It Fl -trace -Print the names of the input files. -.It Fl -trace-symbol Ns = Ns Ar symbol , Fl y Ar symbol -Trace references to -.Ar symbol . -.It Fl -undefined Ns = Ns Ar symbol , Fl u Ar symbol -If -.Ar symbol -is not defined after symbol resolution, and there's a static library -that contains an object file defining the symbol, load the member -to include the object file in the output file. -.It Fl -undefined-glob Ns = Ns Ar pattern -Synonym for -.Fl -undefined , -except that it takes a glob pattern. -In a glob pattern, -.Cm * -matches zero or more characters, -.Cm ? -matches any single character, and -.Cm [...] -matches the characters within brackets. -All symbols that match -a given pattern are handled as if they were given as arguments of -.Fl -undefined . -.It Fl -unique -Creates a separate output section for every orphan input section. -.It Fl -unresolved-symbols Ns = Ns Ar value -Determine how to handle unresolved symbols. -.It Fl -use-android-relr-tags -Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*. -.It Fl v -Display the version number and proceed with linking if object files are -specified. -.It Fl V , Fl -version -Display the version number and exit. -.It Fl -verbose -Verbose mode. -.It Fl -version-script Ns = Ns Ar file -Read version script from -.Ar file . -.It Fl -warn-backrefs -Warn about reverse or cyclic dependencies to or between static archives. -This can be used to ensure linker invocation remains compatible with -traditional Unix-like linkers. -.It Fl -warn-backrefs-exclude Ns = Ns Ar glob -Glob describing an archive (or an object file within --start-lib) -which should be ignored for -.Fl -warn-backrefs -.It Fl -warn-common -Warn about duplicate common symbols. -.It Fl -warn-ifunc-textrel -Warn about using ifunc symbols in conjunction with text relocations. -Older versions of glibc library (2.28 and earlier) has a bug that causes -the segment that includes ifunc symbols to be marked as not executable when -they are relocated. -As a result, although the program compiles and links -successfully, it gives segmentation fault when the instruction pointer reaches -an ifunc symbol. -Use -warn-ifunc-textrel to let lld give a warning, if the -code may include ifunc symbols, may do text relocations and be linked with -an older glibc version. -Otherwise, there is no need to use it, as the default value does not give a -warning. -This flag has been introduced in late 2018, has no counter part in ld and gold -linkers, and may be removed in the future. -.It Fl -warn-unresolved-symbols -Report unresolved symbols as warnings. -.It Fl -whole-archive -Force load of all members in a static library. -.It Fl -wrap Ns = Ns Ar symbol -Redirect -.Ar symbol -references to -.Ar __wrap_symbol -and -.Ar __real_symbol -references to -.Ar symbol. -.It Fl z Ar option -Linker option extensions. -.Bl -tag -width indent -compact -.Pp -.It Cm dead-reloc-in-nonalloc Ns = Ns Ar section_glob=value -Resolve a relocation in a matched non-SHF_ALLOC section referencing a discarded symbol to -.Ar value -Accepts globs, in the event of a section matching more than one option, the last -option takes precedence. An order of least specific to most specific match is -recommended. -.Pp -.It Cm execstack -Make the main stack executable. -Stack permissions are recorded in the -.Dv PT_GNU_STACK -segment. -.Pp -.It Cm force-bti -Force enable AArch64 BTI instruction in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property. -.Pp -.It Cm force-ibt -Force enable Intel Indirect Branch Tracking in PLT, warn if an input ELF file -does not have GNU_PROPERTY_X86_FEATURE_1_IBT property. -.Pp -.It Cm global -Sets the -.Dv DF_1_GLOBAL flag in the -.Dv DYNAMIC -section. -Different loaders can decide how to handle this flag on their own. -.Pp -.It Cm ifunc-noplt -Do not emit PLT entries for ifunc symbols. -Instead, emit text relocations referencing the resolver. -This is an experimental optimization and only suitable for standalone -environments where text relocations do not have the usual drawbacks. -This option must be combined with the -.Fl z Li notext -option. -.Pp -.It Cm initfirst -Sets the -.Dv DF_1_INITFIRST -flag to indicate the module should be initialized first. -.Pp -.It Cm interpose -Set the -.Dv DF_1_INTERPOSE -flag to indicate to the runtime linker that the object is an interposer. -During symbol resolution interposers are searched after the application -but before other dependencies. -.Pp -.It Cm muldefs -Do not error if a symbol is defined multiple times. -The first definition will be used. -This is a synonym for -.Fl -allow-multiple-definition. -.Pp -.It Cm nocombreloc -Disable combining and sorting multiple relocation sections. -.Pp -.It Cm nocopyreloc -Disable the creation of copy relocations. -.Pp -.It Cm nodefaultlib -Set the -.Dv DF_1_NODEFLIB -flag to indicate that default library search paths should be ignored. -.Pp -.It Cm nodelete -Set the -.Dv DF_1_NODELETE -flag to indicate that the object cannot be unloaded from a process. -.Pp -.It Cm nodlopen -Set the -.Dv DF_1_NOOPEN -flag to indicate that the object may not be opened by -.Xr dlopen 3 . -.Pp -.It Cm nognustack -Do not emit the -.Dv PT_GNU_STACK -segment. -.Pp -.It Cm norelro -Do not indicate that portions of the object should be mapped read-only -after initial relocation processing. -The object will omit the -.Dv PT_GNU_RELRO -segment. -.Pp -.It Cm notext -Allow relocations against read-only segments. -Sets the -.Dv DT_TEXTREL flag in the -.Dv DYNAMIC -section. -.Pp -.It Cm now -Set the -.Dv DF_BIND_NOW -flag to indicate that the run-time loader should perform all relocation -processing as part of object initialization. -By default relocations may be performed on demand. -.Pp -.It Cm origin -Set the -.Dv DF_ORIGIN -flag to indicate that the object requires -$ORIGIN -processing. -.Pp -.It Cm pac-plt -AArch64 only, use pointer authentication in PLT. -.Pp -.It Cm rel -Use REL format for dynamic relocations. -.Pp -.It Cm rela -Use RELA format for dynamic relocations. -.Pp -.It Cm retpolineplt -Emit retpoline format PLT entries as a mitigation for CVE-2017-5715. -.Pp -.It Cm rodynamic -Make the -.Li .dynamic -section read-only. -The -.Dv DT_DEBUG -tag will not be emitted. -.Pp -.It Cm separate-loadable-segments -.It Cm separate-code -.It Cm noseparate-code -Specify whether two adjacent PT_LOAD segments are allowed to overlap in pages. -.Cm noseparate-code -(default) allows overlap. -.Cm separate-code -allows overlap between two executable segments, or two non-executable segments. -.Cm separate-loadable-segments -disallows overlap. -.Pp -.It Cm shstk -x86 only, use shadow stack. -.Pp -.It Cm stack-size Ns = Ns Ar size -Set the main thread's stack size to -.Ar size . -The stack size is recorded as the size of the -.Ar size . -.Dv PT_GNU_STACK -program segment. -.Pp -.It Cm start-stop-gc -Don't let __start_/__stop_ references retain the associated C identifier name sections (default). -.Pp -.It Cm nostart-stop-gc -Let __start_/__stop_ references retain the associated C identifier name sections. -.Pp -.It Cm text -Do not allow relocations against read-only segments. -This is the default. -.Pp -.It Cm wxneeded -Create a -.Dv PT_OPENBSD_WXNEEDED -segment. -.El -.El -.Sh IMPLEMENTATION NOTES -.Nm Ap s -handing of archive files (those with a -.Pa .a -file extension) is different from traditional linkers used on Unix-like -systems. -.Pp -Traditional linkers maintain a set of undefined symbols during linking. -The linker processes each file in the order in which it appears on the -command line, until the set of undefined symbols becomes empty. -An object file is linked into the output object when it is encountered, -with its undefined symbols added to the set. -Upon encountering an archive file a traditional linker searches the objects -contained therein, and processes those that satisfy symbols in the unresolved -set. -.Pp -Handling mutually dependent archives may be awkward when using a traditional -linker. -Archive files may have to be specified multiple times, or the special command -line options -.Fl -start-group -and -.Fl -end-group -may be used to have the linker loop over the files in the group until no new -symbols are added to the set. -.Pp -.Nm -records all symbols found in objects and archives as it iterates over -command line arguments. -When -.Nm -encounters an undefined symbol that can be resolved by an object file -contained in a previously processed archive file, it immediately extracts -and links it into the output object. -.Pp -With certain archive inputs -.Nm -may produce different results compared to traditional linkers. -In practice, large bodies of third party software have been linked with -.Nm -without material issues. -.Pp -The -.Fl -warn-backrefs -option may be used to identify a linker invocation that may be incompatible -with traditional Unix-like linker behavior. diff --git a/lld/docs/llvm-theme/layout.html b/lld/docs/llvm-theme/layout.html deleted file mode 100644 index 0cd0918eac..0000000000 --- a/lld/docs/llvm-theme/layout.html +++ /dev/null @@ -1,22 +0,0 @@ -{# - sphinxdoc/layout.html - ~~~~~~~~~~~~~~~~~~~~~ - - Sphinx layout template for the sphinxdoc theme. - - :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{% extends "basic/layout.html" %} - -{% block relbar1 %} - -{{ super() }} -{% endblock %} - -{# put the sidebar before the body #} -{% block sidebar1 %}{{ sidebar() }}{% endblock %} -{% block sidebar2 %}{% endblock %} diff --git a/lld/docs/llvm-theme/static/contents.png b/lld/docs/llvm-theme/static/contents.png deleted file mode 100644 index 7fb82154a1..0000000000 Binary files a/lld/docs/llvm-theme/static/contents.png and /dev/null differ diff --git a/lld/docs/llvm-theme/static/llvm.css b/lld/docs/llvm-theme/static/llvm.css deleted file mode 100644 index 32802bb6a2..0000000000 --- a/lld/docs/llvm-theme/static/llvm.css +++ /dev/null @@ -1,345 +0,0 @@ -/* - * sphinxdoc.css_t - * ~~~~~~~~~~~~~~~ - * - * Sphinx stylesheet -- sphinxdoc theme. Originally created by - * Armin Ronacher for Werkzeug. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; - font-size: 14px; - letter-spacing: -0.01em; - line-height: 150%; - text-align: center; - background-color: #BFD1D4; - color: black; - padding: 0; - border: 1px solid #aaa; - - margin: 0px 80px 0px 80px; - min-width: 740px; -} - -div.logo { - background-color: white; - text-align: left; - padding: 10px 10px 15px 15px; -} - -div.document { - background-color: white; - text-align: left; - background-image: url(contents.png); - background-repeat: repeat-x; -} - -div.bodywrapper { - margin: 0 240px 0 0; - border-right: 1px solid #ccc; -} - -div.body { - margin: 0; - padding: 0.5em 20px 20px 20px; -} - -div.related { - font-size: 1em; -} - -div.related ul { - background-image: url(navigation.png); - height: 2em; - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; -} - -div.related ul li { - margin: 0; - padding: 0; - height: 2em; - float: left; -} - -div.related ul li.right { - float: right; - margin-right: 5px; -} - -div.related ul li a { - margin: 0; - padding: 0 5px 0 5px; - line-height: 1.75em; - color: #EE9816; -} - -div.related ul li a:hover { - color: #3CA8E7; -} - -div.sphinxsidebarwrapper { - padding: 0; -} - -div.sphinxsidebar { - margin: 0; - padding: 0.5em 15px 15px 0; - width: 210px; - float: right; - font-size: 1em; - text-align: left; -} - -div.sphinxsidebar h3, div.sphinxsidebar h4 { - margin: 1em 0 0.5em 0; - font-size: 1em; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border: 1px solid #86989B; - background-color: #AFC1C4; -} - -div.sphinxsidebar h3 a { - color: white; -} - -div.sphinxsidebar ul { - padding-left: 1.5em; - margin-top: 7px; - padding: 0; - line-height: 130%; -} - -div.sphinxsidebar ul ul { - margin-left: 20px; -} - -div.footer { - background-color: #E3EFF1; - color: #86989B; - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: right; -} - -div.footer a { - color: #86989B; - text-decoration: underline; -} - -/* -- body styles ----------------------------------------------------------- */ - -p { - margin: 0.8em 0 0.5em 0; -} - -a { - color: #CA7900; - text-decoration: none; -} - -a:hover { - color: #2491CF; -} - -div.body a { - text-decoration: underline; -} - -h1 { - margin: 0; - padding: 0.7em 0 0.3em 0; - font-size: 1.5em; - color: #11557C; -} - -h2 { - margin: 1.3em 0 0.2em 0; - font-size: 1.35em; - padding: 0; -} - -h3 { - margin: 1em 0 -0.3em 0; - font-size: 1.2em; -} - -div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { - color: black!important; -} - -h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { - display: none; - margin: 0 0 0 0.3em; - padding: 0 0.2em 0 0.2em; - color: #aaa!important; -} - -h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, -h5:hover a.anchor, h6:hover a.anchor { - display: inline; -} - -h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, -h5 a.anchor:hover, h6 a.anchor:hover { - color: #777; - background-color: #eee; -} - -a.headerlink { - color: #c60f0f!important; - font-size: 1em; - margin-left: 6px; - padding: 0 4px 0 4px; - text-decoration: none!important; -} - -a.headerlink:hover { - background-color: #ccc; - color: white!important; -} - -cite, code, tt { - font-family: 'Consolas', 'Deja Vu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.01em; -} - -tt { - background-color: #f2f2f2; - border-bottom: 1px solid #ddd; - color: #333; -} - -tt.descname, tt.descclassname, tt.xref { - border: 0; -} - -hr { - border: 1px solid #abc; - margin: 2em; -} - -a tt { - border: 0; - color: #CA7900; -} - -a tt:hover { - color: #2491CF; -} - -pre { - font-family: 'Consolas', 'Deja Vu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.015em; - line-height: 120%; - padding: 0.5em; - border: 1px solid #ccc; - background-color: #f8f8f8; -} - -pre a { - color: inherit; - text-decoration: underline; -} - -td.linenos pre { - padding: 0.5em 0; -} - -div.quotebar { - background-color: #f8f8f8; - max-width: 250px; - float: right; - padding: 2px 7px; - border: 1px solid #ccc; -} - -div.topic { - background-color: #f8f8f8; -} - -table { - border-collapse: collapse; - margin: 0 -0.5em 0 -0.5em; -} - -table td, table th { - padding: 0.2em 0.5em 0.2em 0.5em; -} - -div.admonition, div.warning { - font-size: 0.9em; - margin: 1em 0 1em 0; - border: 1px solid #86989B; - background-color: #f7f7f7; - padding: 0; -} - -div.admonition p, div.warning p { - margin: 0.5em 1em 0.5em 1em; - padding: 0; -} - -div.admonition pre, div.warning pre { - margin: 0.4em 1em 0.4em 1em; -} - -div.admonition p.admonition-title, -div.warning p.admonition-title { - margin: 0; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border-bottom: 1px solid #86989B; - font-weight: bold; - background-color: #AFC1C4; -} - -div.warning { - border: 1px solid #940000; -} - -div.warning p.admonition-title { - background-color: #CF0000; - border-bottom-color: #940000; -} - -div.admonition ul, div.admonition ol, -div.warning ul, div.warning ol { - margin: 0.1em 0.5em 0.5em 3em; - padding: 0; -} - -div.versioninfo { - margin: 1em 0 0 0; - border: 1px solid #ccc; - background-color: #DDEAF0; - padding: 8px; - line-height: 1.3em; - font-size: 0.9em; -} - -.viewcode-back { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} diff --git a/lld/docs/llvm-theme/static/logo.png b/lld/docs/llvm-theme/static/logo.png deleted file mode 100644 index 4fc899028d..0000000000 Binary files a/lld/docs/llvm-theme/static/logo.png and /dev/null differ diff --git a/lld/docs/llvm-theme/static/navigation.png b/lld/docs/llvm-theme/static/navigation.png deleted file mode 100644 index 1081dc1439..0000000000 Binary files a/lld/docs/llvm-theme/static/navigation.png and /dev/null differ diff --git a/lld/docs/llvm-theme/theme.conf b/lld/docs/llvm-theme/theme.conf deleted file mode 100644 index 330fc92ffa..0000000000 --- a/lld/docs/llvm-theme/theme.conf +++ /dev/null @@ -1,4 +0,0 @@ -[theme] -inherit = basic -stylesheet = llvm.css -pygments_style = friendly diff --git a/lld/docs/make.bat b/lld/docs/make.bat deleted file mode 100644 index 8471252d70..0000000000 --- a/lld/docs/make.bat +++ /dev/null @@ -1,190 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/lld/docs/missingkeyfunction.rst b/lld/docs/missingkeyfunction.rst deleted file mode 100644 index db4ea11b4a..0000000000 --- a/lld/docs/missingkeyfunction.rst +++ /dev/null @@ -1,85 +0,0 @@ -Missing Key Function -==================== - -If your build failed with a linker error something like this:: - - foo.cc:28: error: undefined reference to 'vtable for C' - the vtable symbol may be undefined because the class is missing its key function - (see https://lld.llvm.org/missingkeyfunction) - -it's likely that your class C has a key function (defined by the ABI as the first -non-pure, non-inline, virtual function), but you haven't actually defined it. - -When a class has a key function, the compiler emits the vtable (and some other -things as well) only in the translation unit that defines that key function. Thus, -if you're missing the key function, you'll also be missing the vtable. If no other -function calls your missing function, you won't see any undefined reference errors -for it, but you will see undefined references to the vtable symbol. - -When a class has no non-pure, non-inline, virtual functions, there is no key -function, and the compiler is forced to emit the vtable in every translation unit -that references the class. In this case, it is emitted in a COMDAT section, -which allows the linker to eliminate all duplicate copies. This is still -wasteful in terms of object file size and link time, so it's always advisable to -ensure there is at least one eligible function that can serve as the key function. - -Here are the most common mistakes that lead to this error: - -Failing to define a virtual destructor --------------------------------------- - -Say you have a base class declared in a header file:: - - class B { - public: - B(); - virtual ~B(); - ... - }; - -Here, ``~B`` is the first non-pure, non-inline, virtual function, so it is the key -function. If you forget to define ``B::~B`` in your source file, the compiler will -not emit the vtable for ``B``, and you'll get an undefined reference to "vtable -for B". - -This is just an example of the more general mistake of forgetting to define the -key function, but it's quite common because virtual destructors are likely to be -the first eligible key function and it's easy to forget to implement them. It's -also more likely that you won't have any direct references to the destructor, so -you won't see any undefined reference errors that point directly to the problem. - -The solution in this case is to implement the missing function. - -Forgetting to declare a virtual function in an abstract class as pure ---------------------------------------------------------------------- - -Say you have an abstract base class declared in a header file:: - - class A { - public: - A(); - virtual ~A() {} - virtual int foo() = 0; - ... - virtual int bar(); - ... - }; - -This base class is intended to be abstract, but you forgot to mark one of the -functions pure. Here, ``A::bar``, being non-pure, is nominated as the key function, -and as a result, the vtable for ``A`` is not emitted, because the compiler is -waiting for a translation unit that defines ``A::bar``. - -The solution in this case is to add the missing ``= 0`` to the declaration of -``A::bar``. - -Key function is defined, but the linker doesn't see it ------------------------------------------------------- - -It's also possible that you have defined the key function somewhere, but the -object file containing the definition of that function isn't being linked into -your application. - -The solution in this case is to check your dependencies to make sure that -the object file or the library file containing the key function is given to -the linker. diff --git a/lld/docs/open_projects.rst b/lld/docs/open_projects.rst deleted file mode 100644 index 36edca4e96..0000000000 --- a/lld/docs/open_projects.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _open_projects: - -Open Projects -============= - -Documentation TODOs -~~~~~~~~~~~~~~~~~~~ - -.. todolist:: diff --git a/lld/docs/partitions.dot b/lld/docs/partitions.dot deleted file mode 100644 index 81f12a2f42..0000000000 --- a/lld/docs/partitions.dot +++ /dev/null @@ -1,22 +0,0 @@ -digraph G { - part_main [label="Main partition",shape=plaintext]; - part1 [label="Loadable partition 1",shape=plaintext]; - part2 [label="Loadable partition 2",shape=plaintext]; - main [style=filled,fillcolor=lightblue]; - f1 [style=filled,fillcolor=lightsalmon]; - f2 [style=filled,fillcolor=palegreen]; - f3 [style=filled,fillcolor=lightblue]; - f4 [style=filled,fillcolor=lightsalmon]; - f5 [style=filled,fillcolor=lightblue]; - f6 [style=filled,fillcolor=palegreen]; - part_main -> main; - main -> f3; - part1 -> f1; - f1 -> f3; - f1 -> f4; - f1 -> f5; - part2 -> f2; - f2 -> f3; - f2 -> f5; - f2 -> f6; -} diff --git a/lld/docs/partitions.svg b/lld/docs/partitions.svg deleted file mode 100644 index 39cd969334..0000000000 --- a/lld/docs/partitions.svg +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - -G - - -part_main -Main partition - - -main - -main - - -part_main->main - - - - -part1 -Loadable partition 1 - - -f1 - -f1 - - -part1->f1 - - - - -part2 -Loadable partition 2 - - -f2 - -f2 - - -part2->f2 - - - - -f3 - -f3 - - -main->f3 - - - - -f1->f3 - - - - -f4 - -f4 - - -f1->f4 - - - - -f5 - -f5 - - -f1->f5 - - - - -f2->f3 - - - - -f2->f5 - - - - -f6 - -f6 - - -f2->f6 - - - - - diff --git a/lld/docs/sphinx_intro.rst b/lld/docs/sphinx_intro.rst deleted file mode 100644 index b671cdc3df..0000000000 --- a/lld/docs/sphinx_intro.rst +++ /dev/null @@ -1,127 +0,0 @@ -.. _sphinx_intro: - -Sphinx Introduction for LLVM Developers -======================================= - -This document is intended as a short and simple introduction to the Sphinx -documentation generation system for LLVM developers. - -Quickstart ----------- - -To get started writing documentation, you will need to: - - 1. Have the Sphinx tools :ref:`installed `. - - 2. Understand how to :ref:`build the documentation - `. - - 3. Start :ref:`writing documentation `! - -.. _installing_sphinx: - -Installing Sphinx -~~~~~~~~~~~~~~~~~ - -You should be able to install Sphinx using the standard Python package -installation tool ``easy_install``, as follows:: - - $ sudo easy_install sphinx - Searching for sphinx - Reading http://pypi.python.org/simple/sphinx/ - Reading http://sphinx.pocoo.org/ - Best match: Sphinx 1.1.3 - ... more lines here .. - -If you do not have root access (or otherwise want to avoid installing Sphinx in -system directories) see the section on :ref:`installing_sphinx_in_a_venv` . - -If you do not have the ``easy_install`` tool on your system, you should be able -to install it using: - - Linux - Use your distribution's standard package management tool to install it, - i.e., ``apt-get install easy_install`` or ``yum install easy_install``. - - macOS - All modern macOS systems come with ``easy_install`` as part of the base - system. - - Windows - See the `setuptools `_ package web - page for instructions. - - -.. _building_the_documentation: - -Building the documentation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In order to build the documentation need to add ``-DLLVM_ENABLE_SPHINX=ON`` to -your ``cmake`` command. Once you do this you can build the docs using -``docs-lld-html`` build (``ninja`` or ``make``) target. - -That build target will invoke ``sphinx-build`` with the appropriate options for -the project, and generate the HTML documentation in a ``tools/lld/docs/html`` -subdirectory. - -.. _writing_documentation: - -Writing documentation -~~~~~~~~~~~~~~~~~~~~~ - -The documentation itself is written in the reStructuredText (ReST) format, and -Sphinx defines additional tags to support features like cross-referencing. - -The ReST format itself is organized around documents mostly being readable -plaintext documents. You should generally be able to write new documentation -easily just by following the style of the existing documentation. - -If you want to understand the formatting of the documents more, the best place -to start is Sphinx's own `ReST Primer `_. - - -Learning More -------------- - -If you want to learn more about the Sphinx system, the best place to start is -the Sphinx documentation itself, available `here -`_. - - -.. _installing_sphinx_in_a_venv: - -Installing Sphinx in a Virtual Environment ------------------------------------------- - -Most Python developers prefer to work with tools inside a *virtualenv* (virtual -environment) instance, which functions as an application sandbox. This avoids -polluting your system installation with different packages used by various -projects (and ensures that dependencies for different packages don't conflict -with one another). Of course, you need to first have the virtualenv software -itself which generally would be installed at the system level:: - - $ sudo easy_install virtualenv - -but after that you no longer need to install additional packages in the system -directories. - -Once you have the *virtualenv* tool itself installed, you can create a -virtualenv for Sphinx using:: - - $ virtualenv ~/my-sphinx-install - New python executable in /Users/dummy/my-sphinx-install/bin/python - Installing setuptools............done. - Installing pip...............done. - - $ ~/my-sphinx-install/bin/easy_install sphinx - ... install messages here ... - -and from now on you can "activate" the *virtualenv* using:: - - $ source ~/my-sphinx-install/bin/activate - -which will change your PATH to ensure the sphinx-build tool from inside the -virtual environment will be used. See the `virtualenv website -`_ for more information on using -virtual environments. diff --git a/lld/docs/windows_support.rst b/lld/docs/windows_support.rst deleted file mode 100644 index 620040ee81..0000000000 --- a/lld/docs/windows_support.rst +++ /dev/null @@ -1,97 +0,0 @@ -.. raw:: html - - - -.. role:: none -.. role:: partial -.. role:: good - -=============== -Windows support -=============== - -LLD supports Windows operating system. When invoked as ``lld-link.exe`` or with -``-flavor link``, the driver for Windows operating system is used to parse -command line options, and it drives further linking processes. LLD accepts -almost all command line options that the linker shipped with Microsoft Visual -C++ (link.exe) supports. - -The current status is that LLD is used to link production builds of large -real-world binaries such as Firefox and Chromium. - -Development status -================== - -Driver - :good:`Mostly done`. Some exotic command line options that are not usually - used for application development, such as ``/DRIVER``, are not supported. - -Linking against DLL - :good:`Done`. LLD can read import libraries needed to link against DLL. Both - export-by-name and export-by-ordinal are supported. - -Linking against static library - :good:`Done`. The format of static library (.lib) on Windows is actually the - same as on Unix (.a). LLD can read it. - -Creating DLL - :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported - functions can be specified either via command line (``/EXPORT``) or via - module-definition file (.def). Both export-by-name and export-by-ordinal are - supported. - -Windows resource files support - :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF - file using LLVM's Object library. - -Safe Structured Exception Handler (SEH) - :good:`Done` for both x86 and x64. - -Module-definition file - :partial:`Partially done`. LLD currently recognizes these directives: - ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``. - -Debug info - :good:`Done`. LLD can emit PDBs that are at parity with those generated by - link.exe. However, LLD does not support /DEBUG:FASTLINK. - - -Downloading LLD -=============== - -The Windows version of LLD is included in the `pre-built binaries of LLVM's -releases `_ and in the `LLVM Snapshot -Builds `_. - -Building LLD -============ - -Using Visual Studio IDE/MSBuild -------------------------------- - -1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror), -#. run ``cmake -G "Visual Studio 12" `` from VS command prompt, -#. open LLVM.sln with Visual Studio, and -#. build ``lld`` target in ``lld executables`` folder - -Alternatively, you can use msbuild if you don't like to work in an IDE:: - - msbuild LLVM.sln /m /target:"lld executables\lld" - -MSBuild.exe had been shipped as a component of the .NET framework, but since -2013 it's part of Visual Studio. You can find it at "C:\\Program Files -(x86)\\msbuild". - -You can build LLD as a 64 bit application. To do that, open VS2013 x64 command -prompt and run cmake for "Visual Studio 12 Win64" target. - -Using Ninja ------------ - -1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror), -#. run ``cmake -G ninja `` from VS command prompt, -#. run ``ninja lld`` diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake index 0c3419390c..cfcbb8f8ae 100644 --- a/llvm/cmake/modules/HandleLLVMOptions.cmake +++ b/llvm/cmake/modules/HandleLLVMOptions.cmake @@ -316,12 +316,11 @@ if( LLVM_ENABLE_PIC ) # Note: GCC<10.3 has a bug on SystemZ. # # Note: Clang allows IPO for -fPIC so this optimization is less effective. - # Older Clang may support -fno-semantic-interposition but it used local - # aliases to optimize global variables, which is incompatible with copy - # relocations due to -fno-pic. + # Clang 13 has a bug related to -fsanitize-coverage + # -fno-semantic-interposition (https://reviews.llvm.org/D117183). if ((CMAKE_COMPILER_IS_GNUCXX AND NOT (LLVM_NATIVE_ARCH STREQUAL "SystemZ" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.3)) - OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 13)) + OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 14)) add_flag_if_supported("-fno-semantic-interposition" FNO_SEMANTIC_INTERPOSITION) endif() endif() diff --git a/llvm/include/llvm/Analysis/LazyCallGraph.h b/llvm/include/llvm/Analysis/LazyCallGraph.h index 81500905c0..148be34aa7 100644 --- a/llvm/include/llvm/Analysis/LazyCallGraph.h +++ b/llvm/include/llvm/Analysis/LazyCallGraph.h @@ -1098,28 +1098,10 @@ class LazyCallGraph { continue; } - // The blockaddress constant expression is a weird special case, we can't - // generically walk its operands the way we do for all other constants. - if (BlockAddress *BA = dyn_cast(C)) { - // If we've already visited the function referred to by the block - // address, we don't need to revisit it. - if (Visited.count(BA->getFunction())) - continue; - - // If all of the blockaddress' users are instructions within the - // referred to function, we don't need to insert a cycle. - if (llvm::all_of(BA->users(), [&](User *U) { - if (Instruction *I = dyn_cast(U)) - return I->getFunction() == BA->getFunction(); - return false; - })) - continue; - - // Otherwise we should go visit the referred to function. - Visited.insert(BA->getFunction()); - Worklist.push_back(BA->getFunction()); + // blockaddresses are weird and don't participate in the call graph anyway, + // skip them. + if (isa(C)) continue; - } for (Value *Op : C->operand_values()) if (Visited.insert(cast(Op)).second) diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h index 05d0591f1e..35c3315391 100644 --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -1922,9 +1922,7 @@ class TargetInstrInfo : public MCInstrInfo { /// Optional target hook that returns true if \p MBB is safe to outline from, /// and returns any target-specific information in \p Flags. virtual bool isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, - unsigned &Flags) const { - return true; - } + unsigned &Flags) const; /// Insert a custom frame for outlined functions. virtual void buildOutlinedFrame(MachineBasicBlock &MBB, MachineFunction &MF, diff --git a/llvm/include/llvm/IR/Metadata.h b/llvm/include/llvm/IR/Metadata.h index c584056445..17a9c3a77f 100644 --- a/llvm/include/llvm/IR/Metadata.h +++ b/llvm/include/llvm/IR/Metadata.h @@ -897,6 +897,7 @@ struct TempMDNodeDeleter { class MDNode : public Metadata { friend class ReplaceableMetadataImpl; friend class LLVMContextImpl; + friend class DIArgList; unsigned NumOperands; unsigned NumUnresolved; diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp index e7445e225d..1da712eb9d 100644 --- a/llvm/lib/Analysis/AliasAnalysis.cpp +++ b/llvm/lib/Analysis/AliasAnalysis.cpp @@ -697,14 +697,16 @@ ModRefInfo AAResults::getModRefInfo(const Instruction *I, case Instruction::AtomicRMW: return getModRefInfo((const AtomicRMWInst *)I, Loc, AAQIP); case Instruction::Call: - return getModRefInfo((const CallInst *)I, Loc, AAQIP); + case Instruction::CallBr: case Instruction::Invoke: - return getModRefInfo((const InvokeInst *)I, Loc, AAQIP); + return getModRefInfo((const CallBase *)I, Loc, AAQIP); case Instruction::CatchPad: return getModRefInfo((const CatchPadInst *)I, Loc, AAQIP); case Instruction::CatchRet: return getModRefInfo((const CatchReturnInst *)I, Loc, AAQIP); default: + assert(!I->mayReadOrWriteMemory() && + "Unhandled memory access instruction!"); return ModRefInfo::NoModRef; } } diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp index 4c2413e144..e8f79a28a8 100644 --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -354,6 +354,7 @@ class CallAnalyzer : public InstVisitor { bool simplifyCallSite(Function *F, CallBase &Call); template bool simplifyInstruction(Instruction &I, Callable Evaluate); + bool simplifyIntrinsicCallIsConstant(CallBase &CB); ConstantInt *stripAndComputeInBoundsConstantOffsets(Value *&V); /// Return true if the given argument to the function being considered for @@ -1471,6 +1472,27 @@ bool CallAnalyzer::simplifyInstruction(Instruction &I, Callable Evaluate) { return true; } +/// Try to simplify a call to llvm.is.constant. +/// +/// Duplicate the argument checking from CallAnalyzer::simplifyCallSite since +/// we expect calls of this specific intrinsic to be infrequent. +/// +/// FIXME: Given that we know CB's parent (F) caller +/// (CandidateCall->getParent()->getParent()), we might be able to determine +/// whether inlining F into F's caller would change how the call to +/// llvm.is.constant would evaluate. +bool CallAnalyzer::simplifyIntrinsicCallIsConstant(CallBase &CB) { + Value *Arg = CB.getArgOperand(0); + auto *C = dyn_cast(Arg); + + if (!C) + C = dyn_cast_or_null(SimplifiedValues.lookup(Arg)); + + Type *RT = CB.getFunctionType()->getReturnType(); + SimplifiedValues[&CB] = ConstantInt::get(RT, C ? 1 : 0); + return true; +} + bool CallAnalyzer::visitBitCast(BitCastInst &I) { // Propagate constants through bitcasts. if (simplifyInstruction(I, [&](SmallVectorImpl &COps) { @@ -2091,6 +2113,8 @@ bool CallAnalyzer::visitCallBase(CallBase &Call) { if (auto *SROAArg = getSROAArgForValueOrNull(II->getOperand(0))) SROAArgValues[II] = SROAArg; return true; + case Intrinsic::is_constant: + return simplifyIntrinsicCallIsConstant(Call); } } diff --git a/llvm/lib/CodeGen/RegAllocFast.cpp b/llvm/lib/CodeGen/RegAllocFast.cpp index 707161d5a8..68920e2e50 100644 --- a/llvm/lib/CodeGen/RegAllocFast.cpp +++ b/llvm/lib/CodeGen/RegAllocFast.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SparseSet.h" @@ -432,7 +433,7 @@ void RegAllocFast::spill(MachineBasicBlock::iterator Before, Register VirtReg, // every definition of it, meaning we can switch all the DBG_VALUEs over // to just reference the stack slot. SmallVectorImpl &LRIDbgOperands = LiveDbgValueMap[VirtReg]; - SmallDenseMap> + SmallMapVector, 2> SpilledOperandsMap; for (MachineOperand *MO : LRIDbgOperands) SpilledOperandsMap[MO->getParent()].push_back(MO); diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp index 2e4a656ea0..4bbb5beb21 100644 --- a/llvm/lib/CodeGen/TargetInstrInfo.cpp +++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp @@ -1417,3 +1417,16 @@ std::string TargetInstrInfo::createMIROperandComment( } TargetInstrInfo::PipelinerLoopInfo::~PipelinerLoopInfo() {} + +bool TargetInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, + unsigned &Flags) const { + // Some instrumentations create special TargetOpcode at the start which + // expands to special code sequences which must be present. + auto First = MBB.getFirstNonDebugInstr(); + if (First != MBB.end() && + (First->getOpcode() == TargetOpcode::FENTRY_CALL || + First->getOpcode() == TargetOpcode::PATCHABLE_FUNCTION_ENTER)) + return false; + + return true; +} diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 7b0dab799e..2180eedb58 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1592,6 +1592,12 @@ void DIArgList::handleChangedOperand(void *Ref, Metadata *New) { assert((!New || isa(New)) && "DIArgList must be passed a ValueAsMetadata"); untrack(); + bool Uniq = isUniqued(); + if (Uniq) { + // We need to update the uniqueness once the Args are updated since they + // form the key to the DIArgLists store. + eraseFromStore(); + } ValueAsMetadata *NewVM = cast_or_null(New); for (ValueAsMetadata *&VM : Args) { if (&VM == OldVMPtr) { @@ -1601,6 +1607,10 @@ void DIArgList::handleChangedOperand(void *Ref, Metadata *New) { VM = ValueAsMetadata::get(UndefValue::get(VM->getValue()->getType())); } } + if (Uniq) { + if (uniquify() != this) + storeDistinctInContext(); + } track(); } void DIArgList::track() { diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp index 99819602c5..85ac63eaa1 100644 --- a/llvm/lib/IR/LLVMContextImpl.cpp +++ b/llvm/lib/IR/LLVMContextImpl.cpp @@ -55,8 +55,15 @@ LLVMContextImpl::~LLVMContextImpl() { // Drop references for MDNodes. Do this before Values get deleted to avoid // unnecessary RAUW when nodes are still unresolved. - for (auto *I : DistinctMDNodes) + for (auto *I : DistinctMDNodes) { + // We may have DIArgList that were uniqued, and as it has a custom + // implementation of dropAllReferences, it needs to be explicitly invoked. + if (auto *AL = dyn_cast(I)) { + AL->dropAllReferences(); + continue; + } I->dropAllReferences(); + } #define HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS) \ for (auto *I : CLASS##s) \ I->dropAllReferences(); diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 2ae23fdc95..655319eb1c 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -391,8 +391,9 @@ template <> struct MDNodeKeyImpl { IsUnsigned(N->isUnsigned()) {} bool isKeyOf(const DIEnumerator *RHS) const { - return APInt::isSameValue(Value, RHS->getValue()) && - IsUnsigned == RHS->isUnsigned() && Name == RHS->getRawName(); + return Value.getBitWidth() == RHS->getValue().getBitWidth() && + Value == RHS->getValue() && IsUnsigned == RHS->isUnsigned() && + Name == RHS->getRawName(); } unsigned getHashValue() const { return hash_combine(Value, Name); } diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index 091a62aa4a..f29bb83c2d 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -6923,6 +6923,8 @@ bool AArch64InstrInfo::isFunctionSafeToOutlineFrom( bool AArch64InstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, unsigned &Flags) const { + if (!TargetInstrInfo::isMBBSafeToOutlineFrom(MBB, Flags)) + return false; // Check if LR is available through all of the MBB. If it's not, then set // a flag. assert(MBB.getParent()->getRegInfo().tracksLiveness() && diff --git a/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp index 8c34027f7b..94a0ce09af 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp @@ -13,6 +13,8 @@ #include "AArch64RegisterBankInfo.h" #include "AArch64InstrInfo.h" +#include "AArch64RegisterInfo.h" +#include "MCTargetDesc/AArch64MCTargetDesc.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" @@ -271,6 +273,7 @@ AArch64RegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC, case AArch64::WSeqPairsClassRegClassID: case AArch64::XSeqPairsClassRegClassID: case AArch64::MatrixIndexGPR32_12_15RegClassID: + case AArch64::GPR64_with_sub_32_in_MatrixIndexGPR32_12_15RegClassID: return getRegBank(AArch64::GPRRegBankID); case AArch64::CCRRegClassID: return getRegBank(AArch64::CCRegBankID); diff --git a/llvm/lib/Target/ARM/ARMCallLowering.cpp b/llvm/lib/Target/ARM/ARMCallLowering.cpp index aff7ec8d2e..256a95b94f 100644 --- a/llvm/lib/Target/ARM/ARMCallLowering.cpp +++ b/llvm/lib/Target/ARM/ARMCallLowering.cpp @@ -525,7 +525,7 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo & MIRBuilder.buildInstr(ARM::ADJCALLSTACKUP) .addImm(ArgAssigner.StackOffset) - .addImm(0) + .addImm(-1ULL) .add(predOps(ARMCC::AL)); return true; diff --git a/llvm/lib/Target/ARM/ARMFastISel.cpp b/llvm/lib/Target/ARM/ARMFastISel.cpp index 28a076edd6..9224c2221f 100644 --- a/llvm/lib/Target/ARM/ARMFastISel.cpp +++ b/llvm/lib/Target/ARM/ARMFastISel.cpp @@ -2022,7 +2022,7 @@ bool ARMFastISel::FinishCall(MVT RetVT, SmallVectorImpl &UsedRegs, unsigned AdjStackUp = TII.getCallFrameDestroyOpcode(); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AdjStackUp)) - .addImm(NumBytes).addImm(0)); + .addImm(NumBytes).addImm(-1ULL)); // Now the return value. if (RetVT != MVT::isVoid) { diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp index 9c7055deaa..7c238a1099 100644 --- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -79,6 +79,10 @@ class ARMDAGToDAGISel : public SelectionDAGISel { void Select(SDNode *N) override; + /// Return true as some complex patterns, like those that call + /// canExtractShiftFromMul can modify the DAG inplace. + bool ComplexPatternFuncMutatesDAG() const override { return true; } + bool hasNoVMLxHazardUse(SDNode *N) const; bool isShifterOpProfitable(const SDValue &Shift, ARM_AM::ShiftOpc ShOpcVal, unsigned ShAmt); diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 207101763a..7dab7a52ac 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -999,7 +999,7 @@ bool RISCVInstrInfo::isFunctionSafeToOutlineFrom( bool RISCVInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, unsigned &Flags) const { // More accurate safety checking is done in getOutliningCandidateInfo. - return true; + return TargetInstrInfo::isMBBSafeToOutlineFrom(MBB, Flags); } // Enum values indicating how an outlined call should be constructed. diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index f3b1e6ca70..4b13b5b540 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -44076,32 +44076,9 @@ static SDValue combineVectorHADDSUB(SDNode *N, SelectionDAG &DAG, "Unexpected horizontal add/sub opcode"); if (!shouldUseHorizontalOp(true, DAG, Subtarget)) { - // For slow-hop targets, if we have a hop with a single op, see if we already - // have another user that we can reuse and shuffle the result. MVT VT = N->getSimpleValueType(0); SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); - if (VT.is128BitVector() && LHS == RHS) { - for (SDNode *User : LHS->uses()) { - if (User != N && User->getOpcode() == N->getOpcode()) { - MVT ShufVT = VT.isFloatingPoint() ? MVT::v4f32 : MVT::v4i32; - if (User->getOperand(0) == LHS && !User->getOperand(1).isUndef()) { - return DAG.getBitcast( - VT, - DAG.getVectorShuffle(ShufVT, SDLoc(N), - DAG.getBitcast(ShufVT, SDValue(User, 0)), - DAG.getUNDEF(ShufVT), {0, 1, 0, 1})); - } - if (User->getOperand(1) == LHS && !User->getOperand(0).isUndef()) { - return DAG.getBitcast( - VT, - DAG.getVectorShuffle(ShufVT, SDLoc(N), - DAG.getBitcast(ShufVT, SDValue(User, 0)), - DAG.getUNDEF(ShufVT), {2, 3, 2, 3})); - } - } - } - } // HOP(HOP'(X,X),HOP'(Y,Y)) -> HOP(PERMUTE(HOP'(X,Y)),PERMUTE(HOP'(X,Y)). if (LHS != RHS && LHS.getOpcode() == N->getOpcode() && diff --git a/llvm/lib/Target/X86/X86InstrSystem.td b/llvm/lib/Target/X86/X86InstrSystem.td index 48c27051a8..355ddf26e3 100644 --- a/llvm/lib/Target/X86/X86InstrSystem.td +++ b/llvm/lib/Target/X86/X86InstrSystem.td @@ -583,7 +583,7 @@ def XRSTORS64 : RI<0xC7, MRM3m, (outs), (ins opaquemem:$dst), //===----------------------------------------------------------------------===// // VIA PadLock crypto instructions let Defs = [RAX, RDI], Uses = [RDX, RDI], SchedRW = [WriteSystem] in - def XSTORE : I<0xa7, MRM_C0, (outs), (ins), "xstore", []>, TB, REP; + def XSTORE : I<0xa7, MRM_C0, (outs), (ins), "xstore", []>, TB; def : InstAlias<"xstorerng", (XSTORE)>; diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index b6932dbbfc..fc83befe39 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -29,6 +29,7 @@ #include "llvm/Analysis/CFG.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/LazyCallGraph.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" @@ -1174,6 +1175,15 @@ scanPHIsAndUpdateValueMap(Instruction *Prev, BasicBlock *NewBlock, static bool simplifyTerminatorLeadingToRet(Instruction *InitialInst) { DenseMap ResolvedValues; BasicBlock *UnconditionalSucc = nullptr; + assert(InitialInst->getModule()); + const DataLayout &DL = InitialInst->getModule()->getDataLayout(); + + auto TryResolveConstant = [&ResolvedValues](Value *V) { + auto It = ResolvedValues.find(V); + if (It != ResolvedValues.end()) + V = It->second; + return dyn_cast(V); + }; Instruction *I = InitialInst; while (I->isTerminator() || @@ -1190,47 +1200,65 @@ static bool simplifyTerminatorLeadingToRet(Instruction *InitialInst) { } if (auto *BR = dyn_cast(I)) { if (BR->isUnconditional()) { - BasicBlock *BB = BR->getSuccessor(0); + BasicBlock *Succ = BR->getSuccessor(0); if (I == InitialInst) - UnconditionalSucc = BB; - scanPHIsAndUpdateValueMap(I, BB, ResolvedValues); - I = BB->getFirstNonPHIOrDbgOrLifetime(); + UnconditionalSucc = Succ; + scanPHIsAndUpdateValueMap(I, Succ, ResolvedValues); + I = Succ->getFirstNonPHIOrDbgOrLifetime(); + continue; + } + + BasicBlock *BB = BR->getParent(); + // Handle the case the condition of the conditional branch is constant. + // e.g., + // + // br i1 false, label %cleanup, label %CoroEnd + // + // It is possible during the transformation. We could continue the + // simplifying in this case. + if (ConstantFoldTerminator(BB, /*DeleteDeadConditions=*/true)) { + // Handle this branch in next iteration. + I = BB->getTerminator(); continue; } } else if (auto *CondCmp = dyn_cast(I)) { + // If the case number of suspended switch instruction is reduced to + // 1, then it is simplified to CmpInst in llvm::ConstantFoldTerminator. auto *BR = dyn_cast(I->getNextNode()); - if (BR && BR->isConditional() && CondCmp == BR->getCondition()) { - // If the case number of suspended switch instruction is reduced to - // 1, then it is simplified to CmpInst in llvm::ConstantFoldTerminator. - // And the comparsion looks like : %cond = icmp eq i8 %V, constant. - ConstantInt *CondConst = dyn_cast(CondCmp->getOperand(1)); - if (CondConst && CondCmp->getPredicate() == CmpInst::ICMP_EQ) { - Value *V = CondCmp->getOperand(0); - auto it = ResolvedValues.find(V); - if (it != ResolvedValues.end()) - V = it->second; - - if (ConstantInt *Cond0 = dyn_cast(V)) { - BasicBlock *BB = Cond0->equalsInt(CondConst->getZExtValue()) - ? BR->getSuccessor(0) - : BR->getSuccessor(1); - scanPHIsAndUpdateValueMap(I, BB, ResolvedValues); - I = BB->getFirstNonPHIOrDbgOrLifetime(); - continue; - } - } - } + if (!BR || !BR->isConditional() || CondCmp != BR->getCondition()) + return false; + + // And the comparsion looks like : %cond = icmp eq i8 %V, constant. + // So we try to resolve constant for the first operand only since the + // second operand should be literal constant by design. + ConstantInt *Cond0 = TryResolveConstant(CondCmp->getOperand(0)); + auto *Cond1 = dyn_cast(CondCmp->getOperand(1)); + if (!Cond0 || !Cond1) + return false; + + // Both operands of the CmpInst are Constant. So that we could evaluate + // it immediately to get the destination. + auto *ConstResult = + dyn_cast_or_null(ConstantFoldCompareInstOperands( + CondCmp->getPredicate(), Cond0, Cond1, DL)); + if (!ConstResult) + return false; + + CondCmp->replaceAllUsesWith(ConstResult); + CondCmp->eraseFromParent(); + + // Handle this branch in next iteration. + I = BR; + continue; } else if (auto *SI = dyn_cast(I)) { - Value *V = SI->getCondition(); - auto it = ResolvedValues.find(V); - if (it != ResolvedValues.end()) - V = it->second; - if (ConstantInt *Cond = dyn_cast(V)) { - BasicBlock *BB = SI->findCaseValue(Cond)->getCaseSuccessor(); - scanPHIsAndUpdateValueMap(I, BB, ResolvedValues); - I = BB->getFirstNonPHIOrDbgOrLifetime(); - continue; - } + ConstantInt *Cond = TryResolveConstant(SI->getCondition()); + if (!Cond) + return false; + + BasicBlock *BB = SI->findCaseValue(Cond)->getCaseSuccessor(); + scanPHIsAndUpdateValueMap(I, BB, ResolvedValues); + I = BB->getFirstNonPHIOrDbgOrLifetime(); + continue; } return false; } diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 4e3b18e805..71b3a411cc 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2843,6 +2843,26 @@ static Instruction *tryToMoveFreeBeforeNullTest(CallInst &FI, } assert(FreeInstrBB->size() == 1 && "Only the branch instruction should remain"); + + // Now that we've moved the call to free before the NULL check, we have to + // remove any attributes on its parameter that imply it's non-null, because + // those attributes might have only been valid because of the NULL check, and + // we can get miscompiles if we keep them. This is conservative if non-null is + // also implied by something other than the NULL check, but it's guaranteed to + // be correct, and the conservativeness won't matter in practice, since the + // attributes are irrelevant for the call to free itself and the pointer + // shouldn't be used after the call. + AttributeList Attrs = FI.getAttributes(); + Attrs = Attrs.removeParamAttribute(FI.getContext(), 0, Attribute::NonNull); + Attribute Dereferenceable = Attrs.getParamAttr(0, Attribute::Dereferenceable); + if (Dereferenceable.isValid()) { + uint64_t Bytes = Dereferenceable.getDereferenceableBytes(); + Attrs = Attrs.removeParamAttribute(FI.getContext(), 0, + Attribute::Dereferenceable); + Attrs = Attrs.addDereferenceableOrNullParamAttr(FI.getContext(), 0, Bytes); + } + FI.setAttributes(Attrs); + return &FI; } diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index d22b3f4095..9d8130d1ac 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -1303,17 +1303,10 @@ struct DSEState { /// loop. In particular, this guarantees that it only references a single /// MemoryLocation during execution of the containing function. bool isGuaranteedLoopInvariant(const Value *Ptr) { - auto IsGuaranteedLoopInvariantBase = [this](const Value *Ptr) { + auto IsGuaranteedLoopInvariantBase = [](const Value *Ptr) { Ptr = Ptr->stripPointerCasts(); - if (auto *I = dyn_cast(Ptr)) { - if (isa(Ptr)) - return true; - - if (isAllocLikeFn(I, &TLI)) - return true; - - return false; - } + if (auto *I = dyn_cast(Ptr)) + return I->getParent()->isEntryBlock(); return true; }; diff --git a/llvm/unittests/Analysis/LazyCallGraphTest.cpp b/llvm/unittests/Analysis/LazyCallGraphTest.cpp index b154c6f290..d6e73f3a95 100644 --- a/llvm/unittests/Analysis/LazyCallGraphTest.cpp +++ b/llvm/unittests/Analysis/LazyCallGraphTest.cpp @@ -1978,7 +1978,8 @@ TEST(LazyCallGraphTest, HandleBlockAddress) { LazyCallGraph::Node &G = *CG.lookup(lookupFunction(*M, "g")); EXPECT_EQ(&FRC, CG.lookupRefSCC(F)); EXPECT_EQ(&GRC, CG.lookupRefSCC(G)); - EXPECT_TRUE(GRC.isParentOf(FRC)); + EXPECT_FALSE(GRC.isParentOf(FRC)); + EXPECT_FALSE(FRC.isParentOf(GRC)); } // Test that a blockaddress that refers to itself creates no new RefSCC diff --git a/llvm/unittests/IR/DebugInfoTest.cpp b/llvm/unittests/IR/DebugInfoTest.cpp index 060a5c2b08..17b6e54644 100644 --- a/llvm/unittests/IR/DebugInfoTest.cpp +++ b/llvm/unittests/IR/DebugInfoTest.cpp @@ -7,8 +7,9 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/DebugInfo.h" -#include "llvm/IR/DIBuilder.h" +#include "llvm/ADT/APSInt.h" #include "llvm/AsmParser/Parser.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" @@ -244,4 +245,21 @@ TEST(DIBuilder, CreateSetType) { EXPECT_TRUE(isa_and_nonnull(SetType)); } +TEST(DIBuilder, DIEnumerator) { + LLVMContext Ctx; + std::unique_ptr M(new Module("MyModule", Ctx)); + DIBuilder DIB(*M); + APSInt I1(APInt(32, 1)); + APSInt I2(APInt(33, 1)); + + auto *E = DIEnumerator::get(Ctx, I1, I1.isSigned(), "name"); + EXPECT_TRUE(E); + + auto *E1 = DIEnumerator::getIfExists(Ctx, I1, I1.isSigned(), "name"); + EXPECT_TRUE(E1); + + auto *E2 = DIEnumerator::getIfExists(Ctx, I2, I1.isSigned(), "name"); + EXPECT_FALSE(E2); +} + } // end namespace diff --git a/zig/CMakeLists.txt b/zig/CMakeLists.txt index 39e56ea961..638f39f7e5 100644 --- a/zig/CMakeLists.txt +++ b/zig/CMakeLists.txt @@ -26,7 +26,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) set(ZIG_VERSION_MAJOR 0) set(ZIG_VERSION_MINOR 9) -set(ZIG_VERSION_PATCH 0) +set(ZIG_VERSION_PATCH 1) set(ZIG_VERSION "" CACHE STRING "Override Zig version string. Default is to find out with git.") if("${ZIG_VERSION}" STREQUAL "") @@ -787,7 +787,7 @@ else() set(ZIG1_RELEASE_ARG -OReleaseFast --strip) endif() if(ZIG_SINGLE_THREADED) - set(ZIG1_SINGLE_THREADED_ARG "--single-threaded") + set(ZIG1_SINGLE_THREADED_ARG "-fsingle-threaded") else() set(ZIG1_SINGLE_THREADED_ARG "") endif() diff --git a/zig/CODE_OF_CONDUCT.md b/zig/CODE_OF_CONDUCT.md deleted file mode 100644 index fdde187d01..0000000000 --- a/zig/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,75 +0,0 @@ -# Code of Conduct - -Hello, and welcome! 👋 - -The Zig community is decentralized. Anyone is free to start and maintain their -own space for people to gather, and edit -[the Community wiki page](https://github.com/ziglang/zig/wiki/Community) to add -a link. There is no concept of "official" or "unofficial", however, each -gathering place has its own moderators and rules. - -This is Andrew Kelley speaking. At least for now, I'm the moderator of the -ziglang organization GitHub repositories and the #zig IRC channel on Libera.chat. -**This document contains the rules that govern these two spaces only**. - -The rules here are strict. This space is for focused, on topic, technical work -on the Zig project only. It is everyone's responsibility to maintain a positive -environment, especially when disagreements occur. - -## Our Standards - -Examples of behavior that contribute to creating a positive environment include: - - * Using welcoming and inclusive language. - * Being respectful of differing viewpoints and experiences. - * Gracefully accepting constructive criticism. - * Helping another person accomplish their own goals. - * Showing empathy towards others. - * Showing appreciation for others' work. - * Validating someone else's experience, skills, insight, and use cases. - -Examples of unacceptable behavior by participants include: - - * Unwelcome sexual attention or advances, or use of sexualized language or - imagery that causes discomfort. - * Trolling, insulting/derogatory comments, and personal attacks. Anything - antagonistic towards someone else. - * Off-topic discussion of any kind - especially offensive or sensitive issues. - * Publishing others' private information, such as a physical or electronic - address, without explicit permission. - * Discussing this Code of Conduct or publicly accusing someone of violating it. - * Making someone else feel like an outsider or implying a lack of technical - abilities. - * Destructive behavior. Anything that harms Zig or another open-source project. - -## Enforcement - -If you need to report an issue you can contact me or Loris Cro, who are both -paid by the Zig Software Foundation, and so moderation of this space is part of -our job. We will swiftly remove anyone who is antagonizing others or being -generally destructive. - -This includes Private Harassment. If person A is directly harassed or -antagonized by person B, person B will be blocked from participating in this -space even if the harassment didn't take place on one of the mediums directly -under rule of this Code of Conduct. - -As noted, discussing this Code of Conduct should not take place on GitHub or IRC -because these spaces are for directly working on code, not for meta-discussion. -If you have any issues with it, you can contact me directly, or you can join one -of the community spaces that has different rules. - - * Andrew Kelley - * Loris Cro - -## Conclusion - -Thanks for reading the rules. Together, we can make this space welcoming and -inclusive for everyone, regardless of age, body size, disability, ethnicity, -sex characteristics, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -Sincerely, - -Andrew ✌️ diff --git a/zig/CONTRIBUTING.md b/zig/CONTRIBUTING.md deleted file mode 100644 index acaa2f1b6c..0000000000 --- a/zig/CONTRIBUTING.md +++ /dev/null @@ -1,213 +0,0 @@ -## Contributing - -### Start a Project Using Zig - -One of the best ways you can contribute to Zig is to start using it for a -personal project. Here are some great examples: - - * [Oxid](https://github.com/dbandstra/oxid) - arcade style game - * [TM35-Metronome](https://github.com/TM35-Metronome) - tools for modifying and randomizing Pokémon games - * [River](https://github.com/ifreund/river/) - a dynamic tiling wayland compositor - -More examples can be found on the -[Community Projects Wiki](https://github.com/ziglang/zig/wiki/Community-Projects). - -Without fail, these projects lead to discovering bugs and helping flesh out use -cases, which lead to further design iterations of Zig. Importantly, each issue -found this way comes with real world motivations, so it is easy to explain -your reasoning behind proposals and feature requests. - -Ideally, such a project will help you to learn new skills and add something -to your personal portfolio at the same time. - -### Spread the Word - -Another way to contribute is to write about Zig, or speak about Zig at a -conference, or do either of those things for your project which uses Zig. -Here are some examples: - - * [Iterative Replacement of C with Zig](http://tiehuis.github.io/blog/zig1.html) - * [The Right Tool for the Right Job: Redis Modules & Zig](https://www.youtube.com/watch?v=eCHM8-_poZY) - * [Writing a small ray tracer in Rust and Zig](https://nelari.us/post/raytracer_with_rust_and_zig/) - -Zig is a brand new language, with no advertising budget. Word of mouth is the -only way people find out about the project, and the more people hear about it, -the more people will use it, and the better chance we have to take over the -world. - -### Finding Contributor Friendly Issues - -Please note that issues labeled -[Proposal](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3Aproposal) -but do not also have the -[Accepted](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3Aaccepted) -label are still under consideration, and efforts to implement such a proposal -have a high risk of being wasted. If you are interested in a proposal which is -still under consideration, please express your interest in the issue tracker, -providing extra insights and considerations that others have not yet expressed. -The most highly regarded argument in such a discussion is a real world use case. - -The issue label -[Contributor Friendly](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3A%22contributor+friendly%22) -exists to help you find issues that are **limited in scope and/or -knowledge of Zig internals.** - -### Editing Source Code - -First, build the Stage 1 compiler as described in -[Building Zig From Source](https://github.com/ziglang/zig/wiki/Building-Zig-From-Source). - -Zig locates lib files relative to executable path by searching up the -filesystem tree for a sub-path of `lib/zig/std/std.zig` or `lib/std/std.zig`. -Typically the former is an install and the latter a git working tree which -contains the build directory. - -During development it is not necessary to perform installs when modifying -stage1 or userland sources and in fact it is faster and simpler to run, -test and debug from a git working tree. - -- `make` is typically sufficient to build zig during development iterations. -- `make install` performs a build __and__ install. -- `msbuild -p:Configuration=Release INSTALL.vcxproj` on Windows performs a -build and install. To avoid install, pass cmake option `-DZIG_SKIP_INSTALL_LIB_FILES=ON`. - -To test changes, do the following from the build directory: - -1. Run `make` (on POSIX) or - `msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows). -2. `$BUILD_DIR/zig build test` (on POSIX) or - `$BUILD_DIR/Release\zig.exe build test` (on Windows). - -That runs the whole test suite, which does a lot of extra testing that you -likely won't always need, and can take upwards of 1 hour. This is what the -CI server runs when you make a pull request. (Note: actually it runs a few -more tests; keep reading.) - -To save time, you can add the `--help` option to the `zig build` command and -see what options are available. One of the most helpful ones is -`-Dskip-release`. Adding this option to the command in step 2 above will take -the time down from around 2 hours to about 6 minutes, and this is a good -enough amount of testing before making a pull request. - -Another example is choosing a different set of things to test. For example, -`test-std` instead of `test` will only run the standard library tests, and -not the other ones. Combining this suggestion with the previous one, you could -do this: - -`$BUILD_DIR/bin/zig build test-std -Dskip-release` (on POSIX) or -`$BUILD_DIR/Release\zig.exe build test-std -Dskip-release` (on Windows). - -This will run only the standard library tests, in debug mode only, for all -targets (it will cross-compile the tests for non-native targets but not run -them). - -When making changes to the compiler source code, the most helpful test step to -run is `test-behavior`. When editing documentation it is `docs`. You can find -this information and more in the `--help` menu. - -#### Testing Changes to std lib - -To quickly test a change to a file in the standard library, you can run zig test and specify a custom lib directory with the follow command-line argument. - -```bash -./build/zig test lib/std/fmt.zig --zig-lib-dir lib --main-pkg-path lib/std -``` - -#### Testing Non-Native Architectures with QEMU - -The Linux CI server additionally has qemu installed and sets `-fqemu`. -This provides test coverage for, e.g. aarch64 even on x86_64 machines. It's -recommended for Linux users to install qemu and enable this testing option -when editing the standard library or anything related to a non-native -architecture. - -##### glibc - -Testing foreign architectures with dynamically linked glibc is one step trickier. -This requires enabling `--glibc-runtimes /path/to/glibc/multi/install/glibcs`. -This path is obtained by building glibc for multiple architectures. This -process for me took an entire day to complete and takes up 65 GiB on my hard -drive. The CI server does not provide this test coverage. Instructions for -producing this path can be found -[on the wiki](https://github.com/ziglang/zig/wiki/Updating-libc#glibc). -Just the part with `build-many-glibcs.py`. - -It's understood that most contributors will not have these tests enabled. - -#### Testing Windows from a Linux Machine with Wine - -When developing on Linux, another option is available to you: `-fwine`. -This will enable running behavior tests and std lib tests with Wine. It's -recommended for Linux users to install Wine and enable this testing option -when editing the standard library or anything Windows-related. - -#### Testing WebAssembly using wasmtime - -If you have [wasmtime](https://wasmtime.dev/) installed, take advantage of the -`-fwasmtime` flag which will enable running WASI behavior tests and std -lib tests. It's recommended for all users to install wasmtime and enable this -testing option when editing the standard library and especially anything -WebAssembly-related. - -#### Improving Translate-C - -Please read the [Editing Source Code](#editing-source-code) section as a -prerequisite to this one. - -`translate-c` is a feature provided by Zig that converts C source code into -Zig source code. It powers the `zig translate-c` command as well as -[@cImport](https://ziglang.org/documentation/master/#cImport), allowing Zig -code to not only take advantage of function prototypes defined in .h files, -but also `static inline` functions written in C, and even some macros. - -This feature works by using libclang API to parse and semantically analyze -C/C++ files, and then based on the provided AST and type information, -generating Zig AST, and finally using the mechanisms of `zig fmt` to render -the Zig AST to a file. - -The relevant tests for this feature are: - - * `test/run_translated_c.zig` - each test case is C code with a `main` function. The C code - is translated into Zig code, compiled, and run, and tests that the expected output is the - same, and that the program exits cleanly. This kind of test coverage is preferred, when - possible, because it makes sure that the resulting Zig code is actually viable. - - * `test/stage1/behavior/translate_c_macros.zig` - each test case consists of a Zig test - which checks that the relevant macros in `test/stage1/behavior/translate_c_macros.h`. - have the correct values. Macros have to be tested separately since they are expanded by - Clang in `run_translated_c` tests. - - * `test/translate_c.zig` - each test case is C code, with a list of expected strings which - must be found in the resulting Zig code. This kind of test is more precise in what it - measures, but does not provide test coverage of whether the resulting Zig code is valid. - -This feature is self-hosted, even though Zig is not fully self-hosted yet. In the Zig source -repo, we maintain a C API on top of Clang's C++ API: - - * `src/zig_clang.h` - the C API that we maintain on top of Clang's C++ API. This - file does not include any Clang's C++ headers. Instead, C types and C enums are defined - here. - - * `src/zig_clang.cpp` - a lightweight wrapper that fulfills the C API on top of the - C++ API. It takes advantage of `static_assert` to make sure we get compile errors when - Clang's C++ API changes. This one file necessarily does include Clang's C++ headers, which - makes it the slowest-to-compile source file in all of Zig's codebase. - - * `src/clang.zig` - the Zig equivalent of `src/zig_clang.h`. This is a manually - maintained list of types and functions that are ABI-compatible with the Clang C API we - maintain. In theory this could be generated by running translate-c on `src/zig_clang.h`, - but that would introduce a dependency cycle, since we are using this file to implement - translate-c. - -Finally, the actual source code for the translate-c feature is -`src/translate_c.zig`. This code uses the Clang C API exposed by -`src/clang.zig`, and produces Zig AST. - -The steps for contributing to translate-c look like this: - - 1. Identify a test case you want to improve. Add it as a run-translated-c test - case (usually preferable), or as a translate-c test case. - - 2. Edit `src/translate_c.zig` to improve the behavior. - - 3. Run the relevant tests: `./zig build test-run-translated-c test-translate-c` diff --git a/zig/LICENSE b/zig/LICENSE index 127e1ca7e3..6fda845a81 100644 --- a/zig/LICENSE +++ b/zig/LICENSE @@ -1,6 +1,6 @@ The MIT License (Expat) -Copyright (c) 2015-2021, Zig contributors +Copyright (c) 2015-2022, Zig contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/zig/README.md b/zig/README.md index e98eebf29f..cd8b4b4e96 100644 --- a/zig/README.md +++ b/zig/README.md @@ -1,4 +1,4 @@ -![ZIG](https://ziglang.org/zig-logo.svg) +![ZIG](https://ziglang.org/img/zig-logo-dynamic.svg) A general-purpose programming language and toolchain for maintaining **robust**, **optimal**, and **reusable** software. diff --git a/zig/build.zig b/zig/build.zig index 4e19d47c7f..d33e59dbf3 100644 --- a/zig/build.zig +++ b/zig/build.zig @@ -10,13 +10,13 @@ const fs = std.fs; const InstallDirectoryOptions = std.build.InstallDirectoryOptions; const assert = std.debug.assert; -const zig_version = std.builtin.Version{ .major = 0, .minor = 9, .patch = 0 }; +const zig_version = std.builtin.Version{ .major = 0, .minor = 9, .patch = 1 }; pub fn build(b: *Builder) !void { b.setPreferredReleaseMode(.ReleaseFast); const mode = b.standardReleaseOptions(); const target = b.standardTargetOptions(.{}); - const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode") orelse false; + const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode"); const use_zig_libcxx = b.option(bool, "use-zig-libcxx", "If libc++ is needed, use zig's bundled version, don't try to integrate with the system") orelse false; var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); diff --git a/zig/cmake/Findlld.cmake b/zig/cmake/Findlld.cmake index 5b5fbcb468..8a46888531 100644 --- a/zig/cmake/Findlld.cmake +++ b/zig/cmake/Findlld.cmake @@ -49,6 +49,7 @@ else() FIND_AND_ADD_LLD_LIB(lldELF) FIND_AND_ADD_LLD_LIB(lldCOFF) FIND_AND_ADD_LLD_LIB(lldWasm) + FIND_AND_ADD_LLD_LIB(lldMachO) FIND_AND_ADD_LLD_LIB(lldReaderWriter) FIND_AND_ADD_LLD_LIB(lldCore) FIND_AND_ADD_LLD_LIB(lldYAML) diff --git a/zig/doc/langref.html.in b/zig/doc/langref.html.in index 926b053ca0..c3541c62c0 100644 --- a/zig/doc/langref.html.in +++ b/zig/doc/langref.html.in @@ -1290,13 +1290,39 @@ test "expectError demo" { A variable is a unit of {#link|Memory#} storage.

    - Variables are never allowed to shadow identifiers from an outer scope. -

    -

    It is generally preferable to use {#syntax#}const{#endsyntax#} rather than {#syntax#}var{#endsyntax#} when declaring a variable. This causes less work for both humans and computers to do when reading code, and creates more optimization opportunities.

    + + {#header_open|Identifiers#} +

    + Variable identifiers are never allowed to shadow identifiers from an outer scope. +

    +

    + Identifiers must start with an alphabetic character or underscore and may be followed + by any number of alphanumeric characters or underscores. + They must not overlap with any keywords. See {#link|Keyword Reference#}. +

    +

    + If a name that does not fit these requirements is needed, such as for linking with external libraries, the {#syntax#}@""{#endsyntax#} syntax may be used. +

    + {#code_begin|syntax#} +const @"identifier with spaces in it" = 0xff; +const @"1SmallStep4Man" = 112358; + +const c = @import("std").c; +pub extern "c" fn @"error"() anyopaque; +pub extern "c" fn @"fstat$INODE64"(fd: c.fd_t, buf: *c.Stat) c_int; + +const Color = enum { + red, + @"really red", +}; +const color: Color = .@"really red"; + {#code_end#} + {#header_close#} + {#header_open|Container Level Variables#}

    Container level variables have static lifetime and are order-independent and lazily analyzed. @@ -1481,7 +1507,7 @@ fn divide(a: i32, b: i32) i32 {

    Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on - integer overflow. Alternative operators are provided for wrapping and saturating arithmetic on all targets. + integer overflow. Alternative operators are provided for wrapping and saturating arithmetic on all targets. {#syntax#}+%{#endsyntax#} and {#syntax#}-%{#endsyntax#} perform wrapping arithmetic while {#syntax#}+|{#endsyntax#} and {#syntax#}-|{#endsyntax#} perform saturating arithmetic.

    @@ -2048,7 +2074,7 @@ unwrapped == 1234{#endsyntax#} without evaluating {#syntax#}b{#endsyntax#}. Otherwise, returns {#syntax#}b{#endsyntax#}. -
    {#syntax#}false or true == true{#endsyntax#}
    +
    {#syntax#}(false or true) == true{#endsyntax#}
    @@ -2488,32 +2514,32 @@ test "null terminated array" { or using the shorthand function {#syntax#}std.meta.Vector{#endsyntax#}.

    - Vectors support the same builtin operators as their underlying base types. These operations are performed + Vectors support the same builtin operators as their underlying base types. These operations are performed element-wise, and return a vector of the same length as the input vectors. This includes:

      -
    • Arithmetic ({#syntax#}+{#endsyntax#}, {#syntax#}-{#endsyntax#}, {#syntax#}/{#endsyntax#}, {#syntax#}*{#endsyntax#}, - {#syntax#}@divFloor{#endsyntax#}, {#syntax#}@sqrt{#endsyntax#}, {#syntax#}@ceil{#endsyntax#}, +
    • Arithmetic ({#syntax#}+{#endsyntax#}, {#syntax#}-{#endsyntax#}, {#syntax#}/{#endsyntax#}, {#syntax#}*{#endsyntax#}, + {#syntax#}@divFloor{#endsyntax#}, {#syntax#}@sqrt{#endsyntax#}, {#syntax#}@ceil{#endsyntax#}, {#syntax#}@log{#endsyntax#}, etc.)
    • -
    • Bitwise operators ({#syntax#}>>{#endsyntax#}, {#syntax#}<<{#endsyntax#}, {#syntax#}&{#endsyntax#}, +
    • Bitwise operators ({#syntax#}>>{#endsyntax#}, {#syntax#}<<{#endsyntax#}, {#syntax#}&{#endsyntax#}, {#syntax#}|{#endsyntax#}, {#syntax#}~{#endsyntax#}, etc.)
    • Comparison operators ({#syntax#}<{#endsyntax#}, {#syntax#}>{#endsyntax#}, {#syntax#}=={#endsyntax#}, etc.)

    - It is prohibited to use a math operator on a mixture of scalars (individual numbers) and vectors. - Zig provides the {#link|@splat#} builtin to easily convert from scalars to vectors, and it supports {#link|@reduce#} - and array indexing syntax to convert from vectors to scalars. Vectors also support assignment to and from + It is prohibited to use a math operator on a mixture of scalars (individual numbers) and vectors. + Zig provides the {#link|@splat#} builtin to easily convert from scalars to vectors, and it supports {#link|@reduce#} + and array indexing syntax to convert from vectors to scalars. Vectors also support assignment to and from fixed-length arrays with comptime known length.

    For rearranging elements within and between vectors, Zig provides the {#link|@shuffle#} and {#link|@select#} functions.

    - Operations on vectors shorter than the target machine's native SIMD size will typically compile to single SIMD - instructions, while vectors longer than the target machine's native SIMD size will compile to multiple SIMD - instructions. If a given operation doesn't have SIMD support on the target architecture, the compiler will default - to operating on each vector element one at a time. Zig supports any comptime-known vector length up to 2^32-1, - although small powers of two (2-64) are most typical. Note that excessively long vector lengths (e.g. 2^20) may + Operations on vectors shorter than the target machine's native SIMD size will typically compile to single SIMD + instructions, while vectors longer than the target machine's native SIMD size will compile to multiple SIMD + instructions. If a given operation doesn't have SIMD support on the target architecture, the compiler will default + to operating on each vector element one at a time. Zig supports any comptime-known vector length up to 2^32-1, + although small powers of two (2-64) are most typical. Note that excessively long vector lengths (e.g. 2^20) may result in compiler crashes on current versions of Zig.

    {#code_begin|test|vector_example#} @@ -2563,7 +2589,7 @@ test "Conversion between vectors, arrays, and slices" { TODO consider suggesting std.MultiArrayList

    {#see_also|@splat|@shuffle|@select|@reduce#} - + {#header_close#} {#header_open|Pointers#} @@ -2582,7 +2608,7 @@ test "Conversion between vectors, arrays, and slices" {
  • Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}
  • Supports pointer arithmetic: {#syntax#}ptr + x{#endsyntax#}, {#syntax#}ptr - x{#endsyntax#}
  • {#syntax#}T{#endsyntax#} must have a known size, which means that it cannot be - {#syntax#}c_void{#endsyntax#} or any other {#link|opaque type|opaque#}.
  • + {#syntax#}anyopaque{#endsyntax#} or any other {#link|opaque type|opaque#}. @@ -2981,8 +3007,8 @@ test "null terminated slice" { } {#code_end#}

    - Sentinel-terminated slices can also be created using a variation of the slice syntax - {#syntax#}data[start..end :x]{#endsyntax#}, where {#syntax#}data{#endsyntax#} is a many-item pointer, + Sentinel-terminated slices can also be created using a variation of the slice syntax + {#syntax#}data[start..end :x]{#endsyntax#}, where {#syntax#}data{#endsyntax#} is a many-item pointer, array or slice and {#syntax#}x{#endsyntax#} is the sentinel value.

    {#code_begin|test|null_terminated_slicing#} @@ -2999,7 +3025,7 @@ test "null terminated slicing" { } {#code_end#}

    - Sentinel-terminated slicing asserts that the element in the sentinel position of the backing data is + Sentinel-terminated slicing asserts that the element in the sentinel position of the backing data is actually the sentinel value. If this is not the case, safety-protected {#link|Undefined Behavior#} results.

    {#code_begin|test_safety|sentinel mismatch#} @@ -3008,10 +3034,10 @@ const expect = std.testing.expect; test "sentinel mismatch" { var array = [_]u8{ 3, 2, 1, 0 }; - - // Creating a sentinel-terminated slice from the array with a length of 2 - // will result in the value `1` occupying the sentinel element position. - // This does not match the indicated sentinel value of `0` and will lead + + // Creating a sentinel-terminated slice from the array with a length of 2 + // will result in the value `1` occupying the sentinel element position. + // This does not match the indicated sentinel value of `0` and will lead // to a runtime panic. var runtime_length: usize = 2; const slice = array[0..runtime_length :0]; @@ -3159,7 +3185,12 @@ test "linked list" { .last = &node, .len = 1, }; + + // When using a pointer to a struct, fields can be accessed directly, + // without explicitly dereferencing the pointer. + // So you can do try expect(list2.first.?.data == 1234); + // instead of try expect(list2.first.?.*.data == 1234); } {#code_end#} @@ -3486,7 +3517,7 @@ fn dump(args: anytype) !void {

    The fields are implicitly named using numbers starting from 0. Because their names are integers, - the {#syntax#}@"0"{#endsyntax#} syntax must be used to access them. Names inside {#syntax#}@""{#endsyntax#} are always recognised as identifiers. + the {#syntax#}@"0"{#endsyntax#} syntax must be used to access them. Names inside {#syntax#}@""{#endsyntax#} are always recognised as {#link|identifiers|Identifiers#}.

    Like arrays, tuples have a .len field, can be indexed and work with the ++ and ** operators. They can also be iterated over with {#link|inline for#}. @@ -3975,7 +4006,7 @@ test "labeled break from labeled block expression" { {#see_also|Labeled while|Labeled for#} {#header_open|Shadowing#} -

    Identifiers are never allowed to "hide" other identifiers by using the same name:

    +

    {#link|Identifiers#} are never allowed to "hide" other identifiers by using the same name:

    {#code_begin|test_err|local shadows declaration#} const pi = 3.14; @@ -3987,8 +4018,8 @@ test "inside test block" { } {#code_end#}

    - Because of this, when you read Zig code you can always rely on an identifier to consistently mean - the same thing within the scope it is defined. Note that you can, however, use the same name if + Because of this, when you read Zig code you can always rely on an identifier to consistently mean + the same thing within the scope it is defined. Note that you can, however, use the same name if the scopes are separate:

    {#code_begin|test|test_scopes#} @@ -4026,7 +4057,7 @@ test "switch simple" { 1, 2, 3 => 0, // Ranges can be specified using the ... syntax. These are inclusive - // both ends. + // of both ends. 5...100 => 1, // Branches can be arbitrarily complex. @@ -4798,7 +4829,7 @@ test "errdefer unwinding" {

    {#header_open|Basics#} {#code_begin|test|test_unreachable#} -// unreachable is used to assert that control flow will never happen upon a +// unreachable is used to assert that control flow will never reach a // particular location: test "basic math" { const x = 1; @@ -6269,8 +6300,8 @@ test "turn HashMap into a set with void" { value is deleted, as seen above.

    - {#syntax#}void{#endsyntax#} is distinct from {#syntax#}c_void{#endsyntax#}. - {#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}c_void{#endsyntax#} has an unknown, but non-zero, size. + {#syntax#}void{#endsyntax#} is distinct from {#syntax#}anyopaque{#endsyntax#}. + {#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}anyopaque{#endsyntax#} has an unknown, but non-zero, size.

    Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example: @@ -6766,8 +6797,7 @@ test "variable values" { generic data structure.

    - Here is an example of a generic {#syntax#}List{#endsyntax#} data structure, that we will instantiate with - the type {#syntax#}i32{#endsyntax#}. In Zig we refer to the type as {#syntax#}List(i32){#endsyntax#}. + Here is an example of a generic {#syntax#}List{#endsyntax#} data structure.

    {#code_begin|syntax#} fn List(comptime T: type) type { @@ -6776,27 +6806,46 @@ fn List(comptime T: type) type { len: usize, }; } + +// The generic List data structure can be instantiated by passing in a type: +var buffer: [10]i32 = undefined; +var list = List(i32){ + .items = &buffer, + .len = 0, +}; {#code_end#}

    - That's it. It's a function that returns an anonymous {#syntax#}struct{#endsyntax#}. For the purposes of error messages - and debugging, Zig infers the name {#syntax#}"List(i32)"{#endsyntax#} from the function name and parameters invoked when creating + That's it. It's a function that returns an anonymous {#syntax#}struct{#endsyntax#}. + To keep the language small and uniform, all aggregate types in Zig are anonymous. + For the purposes of error messages and debugging, Zig infers the name + {#syntax#}"List(i32)"{#endsyntax#} from the function name and parameters invoked when creating the anonymous struct.

    - To keep the language small and uniform, all aggregate types in Zig are anonymous. To give a type - a name, we assign it to a constant: + To explicitly give a type a name, we assign it to a constant.

    {#code_begin|syntax#} const Node = struct { - next: *Node, - name: []u8, + next: ?*Node, + name: []const u8, +}; + +var node_a = Node{ + .next = null, + .name = &"Node A", +}; + +var node_b = Node{ + .next = &node_a, + .name = &"Node B", }; {#code_end#}

    - This works because all top level declarations are order-independent, and as long as there isn't - an actual infinite regression, values can refer to themselves, directly or indirectly. In this case, - {#syntax#}Node{#endsyntax#} refers to itself as a pointer, which is not actually an infinite regression, so - it works fine. + In this example, the {#syntax#}Node{#endsyntax#} struct refers to itself. + This works because all top level declarations are order-independent. + As long as the compiler can determine the size of the struct, it is free to refer to itself. + In this case, {#syntax#}Node{#endsyntax#} refers to itself as a pointer, which has a + well-defined size at compile time, so it works fine.

    {#header_close#} {#header_open|Case Study: print in Zig#} @@ -7209,10 +7258,10 @@ test "global assembly" { provided explicitly by the caller, and it can be suspended and resumed any number of times.

    - The code following the {#syntax#}async{#endsyntax#} callsite runs immediately after the async - function first suspends. When the return value of the async function is needed, - the calling code can {#syntax#}await{#endsyntax#} on the async function frame. - This will suspend the calling code until the async function completes, at which point + The code following the {#syntax#}async{#endsyntax#} callsite runs immediately after the async + function first suspends. When the return value of the async function is needed, + the calling code can {#syntax#}await{#endsyntax#} on the async function frame. + This will suspend the calling code until the async function completes, at which point execution resumes just after the {#syntax#}await{#endsyntax#} callsite.

    @@ -7322,8 +7371,8 @@ fn testResumeFromSuspend(my_result: *i32) void { in standard code.

    - However, it is possible to have an {#syntax#}async{#endsyntax#} call - without a matching {#syntax#}await{#endsyntax#}. Upon completion of the async function, + However, it is possible to have an {#syntax#}async{#endsyntax#} call + without a matching {#syntax#}await{#endsyntax#}. Upon completion of the async function, execution would continue at the most recent {#syntax#}async{#endsyntax#} callsite or {#syntax#}resume{#endsyntax#} callsite, and the return value of the async function would be lost.

    @@ -7360,8 +7409,8 @@ fn func() void {

    {#syntax#}await{#endsyntax#} is a suspend point, and takes as an operand anything that - coerces to {#syntax#}anyframe->T{#endsyntax#}. Calling {#syntax#}await{#endsyntax#} on - the frame of an async function will cause execution to continue at the + coerces to {#syntax#}anyframe->T{#endsyntax#}. Calling {#syntax#}await{#endsyntax#} on + the frame of an async function will cause execution to continue at the {#syntax#}await{#endsyntax#} callsite once the target function completes.

    @@ -8286,8 +8335,8 @@ fn internalName() callconv(.C) void {} {#code_begin|obj#} export fn foo() void {} {#code_end#} -

    Note that even when using {#syntax#}export{#endsyntax#}, {#syntax#}@"foo"{#endsyntax#} syntax can - be used to choose any string for the symbol name:

    +

    Note that even when using {#syntax#}export{#endsyntax#}, the {#syntax#}@"foo"{#endsyntax#} syntax for + {#link|identifiers|Identifiers#} can be used to choose any string for the symbol name:

    {#code_begin|obj#} export fn @"A function name that is a complete sentence."() void {} {#code_end#} @@ -8518,6 +8567,9 @@ test "@hasDecl" {
  • {#syntax#}@import("builtin"){#endsyntax#} - Target-specific information The command zig build-exe --show-builtin outputs the source to stdout for reference.
  • +
  • {#syntax#}@import("root"){#endsyntax#} - Points to the root source file + This is usually `src/main.zig` but it depends on what file is chosen to be built. +
  • {#see_also|Compile Variables|@embedFile#} {#header_close#} @@ -8529,6 +8581,16 @@ test "@hasDecl" { Attempting to convert a number which is out of range of the destination type results in safety-protected {#link|Undefined Behavior#}.

    + {#code_begin|test_err|cast truncated bits#} +test "integer cast panic" { + var a: u16 = 0xabcd; + var b: u8 = @intCast(u8, a); + _ = b; +} + {#code_end#} +

    + To truncate the significant bits of a number out of range of the destination type, use {#link|@truncate#}. +

    If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#}, then this is semantically equivalent to {#link|Type Coercion#}. @@ -8573,7 +8635,9 @@ test "@hasDecl" { {#header_open|@intToPtr#}

    {#syntax#}@intToPtr(comptime DestType: type, address: usize) DestType{#endsyntax#}

    - Converts an integer to a {#link|pointer|Pointers#}. To convert the other way, use {#link|@ptrToInt#}. + Converts an integer to a {#link|pointer|Pointers#}. To convert the other way, use {#link|@ptrToInt#}. Casting an address of 0 to a destination type + which in not {#link|optional|Optional Pointers#} and does not have the {#syntax#}allowzero{#endsyntax#} attribute will result in a + {#link|Pointer Cast Invalid Null#} panic when runtime safety checks are enabled.

    If the destination pointer type does not allow address zero and {#syntax#}address{#endsyntax#} @@ -8687,7 +8751,8 @@ test "@wasmMemoryGrow" {

    {#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}

    Modulus division. For unsigned integers this is the same as - {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}. + {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the + operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.

    • {#syntax#}@mod(-5, 3) == 1{#endsyntax#}
    • @@ -8705,7 +8770,7 @@ test "@wasmMemoryGrow" { If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.

      {#header_close#} - + {#header_open|@panic#}
      {#syntax#}@panic(message: []const u8) noreturn{#endsyntax#}

      @@ -8812,7 +8877,8 @@ pub const PrefetchOptions = struct {

      {#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}

      Remainder division. For unsigned integers this is the same as - {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}. + {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the + operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.

      • {#syntax#}@rem(-5, 3) == -2{#endsyntax#}
      • @@ -8854,14 +8920,14 @@ pub const PrefetchOptions = struct { {#header_close#} {#header_open|@setCold#} -
        {#syntax#}@setCold(is_cold: bool){#endsyntax#}
        +
        {#syntax#}@setCold(comptime is_cold: bool){#endsyntax#}

        Tells the optimizer that a function is rarely called.

        {#header_close#} {#header_open|@setEvalBranchQuota#} -
        {#syntax#}@setEvalBranchQuota(new_quota: u32){#endsyntax#}
        +
        {#syntax#}@setEvalBranchQuota(comptime new_quota: u32){#endsyntax#}

        Changes the maximum number of backwards branches that compile-time code execution can use before giving up and making a compile error. @@ -8896,7 +8962,7 @@ test "foo" { {#header_close#} {#header_open|@setFloatMode#} -

        {#syntax#}@setFloatMode(mode: @import("std").builtin.FloatMode){#endsyntax#}
        +
        {#syntax#}@setFloatMode(comptime mode: @import("std").builtin.FloatMode){#endsyntax#}

        Sets the floating point mode of the current scope. Possible values are:

        @@ -8931,7 +8997,7 @@ pub const FloatMode = enum { {#header_close#} {#header_open|@setRuntimeSafety#} -
        {#syntax#}@setRuntimeSafety(safety_on: bool) void{#endsyntax#}
        +
        {#syntax#}@setRuntimeSafety(comptime safety_on: bool) void{#endsyntax#}

        Sets whether runtime safety checks are enabled for the scope that contains the function call.

        @@ -8992,7 +9058,7 @@ test "@setRuntimeSafety" {

        {#see_also|@shlExact|@shrExact#} {#header_close#} - + {#header_open|@shrExact#}
        {#syntax#}@shrExact(value: T, shift_amt: Log2T) T{#endsyntax#}

        @@ -9323,7 +9389,7 @@ fn doTheTest() !void { If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.

        {#header_close#} - + {#header_open|@tagName#}
        {#syntax#}@tagName(value: anytype) [:0]const u8{#endsyntax#}

        @@ -9372,17 +9438,11 @@ fn List(comptime T: type) type { or same-sized integer type.

        - The following produces safety-checked {#link|Undefined Behavior#}: + This function always truncates the significant bits of the integer, regardless + of endianness on the target platform.

        - {#code_begin|test_err|cast truncated bits#} -test "integer cast panic" { - var a: u16 = 0xabcd; - var b: u8 = @intCast(u8, a); - _ = b; -} - {#code_end#}

        - However this is well defined and working code: + Calling {#syntax#}@truncate{#endsyntax#} on a number out of range of the destination type is well defined and working code:

        {#code_begin|test|truncate#} const std = @import("std"); @@ -9395,8 +9455,7 @@ test "integer truncation" { } {#code_end#}

        - This function always truncates the significant bits of the integer, regardless - of endianness on the target platform. + Use {#link|@intCast#} to convert numbers guaranteed to fit the destination type.

        {#header_close#} @@ -9448,9 +9507,14 @@ test "integer truncation" { Provides type reflection.

        - For {#link|structs|struct#}, {#link|unions|union#}, {#link|enums|enum#}, and - {#link|error sets|Error Set Type#}, the fields are guaranteed to be in the same - order as declared. For declarations, the order is unspecified. + Type information of {#link|structs|struct#}, {#link|unions|union#}, {#link|enums|enum#}, and + {#link|error sets|Error Set Type#} has fields which are are guaranteed to be in the same + order as appearance in the source file. +

        +

        + Type information of {#link|structs|struct#}, {#link|unions|union#}, {#link|enums|enum#}, and + {#link|opaques|opaque#} has declarations, which are also guaranteed to be in the same + order as appearance in the source file.

        {#header_close#} @@ -10618,8 +10682,10 @@ lib.addCSourceFile("src/lib.c", &[_][]const u8{
      • {#syntax#}c_longlong{#endsyntax#}
      • {#syntax#}c_ulonglong{#endsyntax#}
      • {#syntax#}c_longdouble{#endsyntax#}
      • -
      • {#syntax#}c_void{#endsyntax#}
      +

      + To interop with the C {#syntax#}void{#endsyntax#} type, use {#syntax#}anyopaque{#endsyntax#}. +

      {#see_also|Primitive Types#} {#header_close#} {#header_open|Import from C Header File#} diff --git a/zig/lib/libc/glibc/csu/elf-init-2.33.c b/zig/lib/libc/glibc/csu/elf-init-2.33.c new file mode 100644 index 0000000000..b713c8b0fb --- /dev/null +++ b/zig/lib/libc/glibc/csu/elf-init-2.33.c @@ -0,0 +1,106 @@ +/* Startup support for ELF initializers/finalizers in the main executable. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + + +/* These magic symbols are provided by the linker. */ +extern void (*__preinit_array_start []) (int, char **, char **) + attribute_hidden; +extern void (*__preinit_array_end []) (int, char **, char **) + attribute_hidden; +extern void (*__init_array_start []) (int, char **, char **) + attribute_hidden; +extern void (*__init_array_end []) (int, char **, char **) + attribute_hidden; +extern void (*__fini_array_start []) (void) attribute_hidden; +extern void (*__fini_array_end []) (void) attribute_hidden; + + +#ifndef NO_INITFINI +/* These function symbols are provided for the .init/.fini section entry + points automagically by the linker. */ +extern void _init (void); +extern void _fini (void); +#endif + + +/* These functions are passed to __libc_start_main by the startup code. + These get statically linked into each program. For dynamically linked + programs, this module will come from libc_nonshared.a and differs from + the libc.a module in that it doesn't call the preinit array. */ + + +void +__libc_csu_init (int argc, char **argv, char **envp) +{ + /* For dynamically linked executables the preinit array is executed by + the dynamic linker (before initializing any shared object). */ + +#ifndef LIBC_NONSHARED + /* For static executables, preinit happens right before init. */ + { + const size_t size = __preinit_array_end - __preinit_array_start; + size_t i; + for (i = 0; i < size; i++) + (*__preinit_array_start [i]) (argc, argv, envp); + } +#endif + +#ifndef NO_INITFINI + _init (); +#endif + + const size_t size = __init_array_end - __init_array_start; + for (size_t i = 0; i < size; i++) + (*__init_array_start [i]) (argc, argv, envp); +} + +/* This function should not be used anymore. We run the executable's + destructor now just like any other. We cannot remove the function, + though. */ +void +__libc_csu_fini (void) +{ +#ifndef LIBC_NONSHARED + size_t i = __fini_array_end - __fini_array_start; + while (i-- > 0) + (*__fini_array_start [i]) (); + +# ifndef NO_INITFINI + _fini (); +# endif +#endif +} diff --git a/zig/lib/libc/glibc/sysdeps/aarch64/start-2.33.S b/zig/lib/libc/glibc/sysdeps/aarch64/start-2.33.S new file mode 100644 index 0000000000..d96cf57e2d --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/aarch64/start-2.33.S @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#include + +/* This is the canonical entry point, usually the first thing in the text + segment. + + Note that the code in the .init section has already been run. + This includes _init and _libc_init + + + At this entry point, most registers' values are unspecified, except: + + x0/w0 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + sp The stack contains the arguments and environment: + 0(sp) argc + 8(sp) argv[0] + ... + (8*argc)(sp) NULL + (8*(argc+1))(sp) envp[0] + ... + NULL + */ + + .text + .globl _start + .type _start,#function +_start: + /* Create an initial frame with 0 LR and FP */ + mov x29, #0 + mov x30, #0 + + /* Setup rtld_fini in argument register */ + mov x5, x0 + + /* Load argc and a pointer to argv */ + ldr PTR_REG (1), [sp, #0] + add x2, sp, #PTR_SIZE + + /* Setup stack limit in argument register */ + mov x6, sp + +#ifdef PIC +# ifdef SHARED + adrp x0, :got:main + ldr PTR_REG (0), [x0, #:got_lo12:main] + + adrp x3, :got:__libc_csu_init + ldr PTR_REG (3), [x3, #:got_lo12:__libc_csu_init] + + adrp x4, :got:__libc_csu_fini + ldr PTR_REG (4), [x4, #:got_lo12:__libc_csu_fini] +# else + adrp x0, __wrap_main + add x0, x0, :lo12:__wrap_main + adrp x3, __libc_csu_init + add x3, x3, :lo12:__libc_csu_init + adrp x4, __libc_csu_fini + add x4, x4, :lo12:__libc_csu_fini +# endif +#else + /* Set up the other arguments in registers */ + MOVL (0, main) + MOVL (3, __libc_csu_init) + MOVL (4, __libc_csu_fini) +#endif + + /* __libc_start_main (main, argc, argv, init, fini, rtld_fini, + stack_end) */ + + /* Let the libc call main and exit with its return code. */ + bl __libc_start_main + + /* should never get here....*/ + bl abort + +#if defined PIC && !defined SHARED + /* When main is not defined in the executable but in a shared library + then a wrapper is needed in crt1.o of the static-pie enabled libc, + because crt1.o and rcrt1.o share code and the later must avoid the + use of GOT relocations before __libc_start_main is called. */ +__wrap_main: + b main +#endif + + /* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/alpha/start-2.33.S b/zig/lib/libc/glibc/sysdeps/alpha/start-2.33.S new file mode 100644 index 0000000000..a59898c4c0 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/alpha/start-2.33.S @@ -0,0 +1,85 @@ +/* Startup code for Alpha/ELF. + Copyright (C) 1993-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#include + + .text + .align 3 + .globl _start + .ent _start, 0 + .type _start,@function +_start: + .frame $15, 0, $15 + br gp, 1f +1: ldgp gp, 0(gp) + subq sp, 16, sp + mov 0, $15 + .prologue 0 + + /* Load address of the user's main function. */ + lda a0, main + + ldl a1, 16(sp) /* get argc */ + lda a2, 24(sp) /* get argv */ + + /* Load address of our own entry points to .fini and .init. */ + lda a3, __libc_csu_init + lda a4, __libc_csu_fini + + /* Store address of the shared library termination function. */ + mov v0, a5 + + /* Provide the highest stack address to the user code. */ + stq sp, 0(sp) + + /* Call the user's main function, and exit with its value. + But let the libc call main. */ + jsr ra, __libc_start_main + + /* Die very horribly if exit returns. Call_pal hlt is callable from + kernel mode only; this will result in an illegal instruction trap. */ + call_pal 0 + .end _start + +/* For ECOFF backwards compatibility. */ +weak_alias (_start, __start) + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/arm/start-2.33.S b/zig/lib/libc/glibc/sysdeps/arm/start-2.33.S new file mode 100644 index 0000000000..2ff56179d2 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/arm/start-2.33.S @@ -0,0 +1,148 @@ +/* Startup code for ARM & ELF + Copyright (C) 1995-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +/* This is the canonical entry point, usually the first thing in the text + segment. + + Note that the code in the .init section has already been run. + This includes _init and _libc_init + + + At this entry point, most registers' values are unspecified, except: + + a1 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + sp The stack contains the arguments and environment: + 0(sp) argc + 4(sp) argv[0] + ... + (4*argc)(sp) NULL + (4*(argc+1))(sp) envp[0] + ... + NULL +*/ + +/* Tag_ABI_align8_preserved: This code preserves 8-byte + alignment in any callee. */ + .eabi_attribute 25, 1 +/* Tag_ABI_align8_needed: This code may require 8-byte alignment from + the caller. */ + .eabi_attribute 24, 1 + +#if defined(__thumb2__) + .thumb + .syntax unified +#endif + + .text + .globl _start + .type _start,#function +_start: + /* Protect against unhandled exceptions. */ + .fnstart + /* Clear the frame pointer and link register since this is the outermost frame. */ + mov fp, #0 + mov lr, #0 + + /* Pop argc off the stack and save a pointer to argv */ + pop { a2 } + mov a3, sp + + /* Push stack limit */ + push { a3 } + + /* Push rtld_fini */ + push { a1 } + +#ifdef PIC + ldr sl, .L_GOT + adr a4, .L_GOT + add sl, sl, a4 + + ldr ip, .L_GOT+4 /* __libc_csu_fini */ + ldr ip, [sl, ip] + + push { ip } /* Push __libc_csu_fini */ + + ldr a4, .L_GOT+8 /* __libc_csu_init */ + ldr a4, [sl, a4] + + ldr a1, .L_GOT+12 /* main */ + ldr a1, [sl, a1] + + /* __libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end) */ + /* Let the libc call main and exit with its return code. */ + bl __libc_start_main(PLT) +#else + /* Fetch address of __libc_csu_fini */ + ldr ip, =__libc_csu_fini + + /* Push __libc_csu_fini */ + push { ip } + + /* Set up the other arguments in registers */ + ldr a1, =main + ldr a4, =__libc_csu_init + + /* __libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end) */ + /* Let the libc call main and exit with its return code. */ + bl __libc_start_main +#endif + + /* should never get here....*/ + bl abort + +#ifdef PIC + .align 2 +.L_GOT: + .word _GLOBAL_OFFSET_TABLE_ - .L_GOT + .word __libc_csu_fini(GOT) + .word __libc_csu_init(GOT) + .word main(GOT) +#endif + + .cantunwind + .fnend + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/hppa/start-2.33.S b/zig/lib/libc/glibc/sysdeps/hppa/start-2.33.S new file mode 100644 index 0000000000..c725f002dc --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/hppa/start-2.33.S @@ -0,0 +1,152 @@ +/* ELF startup code for HPPA. + Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + + .import main, code + .import $global$, data + .import __libc_start_main, code + .import __libc_csu_fini, code + .import __libc_csu_init, code + + /* Have the linker create plabel words so we get PLABEL32 + relocs and not 21/14. The use of 21/14 relocs is only + supported in the latest dynamic linker. */ +#ifdef PIC + .section .data.rel.ro,"aw",@progbits +#else + .section .rodata,"a",@progbits +#endif + .align 4 +.Lpmain: + .word P%main +.Lp__libc_start_main: + .word P%__libc_start_main +.Lp__libc_csu_fini: + .word P%__libc_csu_fini +.Lp__libc_csu_init: + .word P%__libc_csu_init + + .text + .align 4 + .globl _start + .export _start, ENTRY + .type _start,@function +_start: + /* At entry to the function we have: + + r26 - Unused + r25 - argc + r24 - argv + r23 - False _dl_fini plabel address + + This function is called from the lower half of RTLD_START. + + The call to __libc_start_main expects: + + 1. r26 - Application main + 2. r25 - argc + 3. r24 - argv + 4. r23 - __libc_csu_init + 5. sp-52 - __libc_csu_fini + 6. sp-56 - rtld_fini + 7. sp-60 - stackend */ + + .proc + .callinfo + /* Clear previous-sp. */ + stw %r0, -4(%sp) + /* Setup the stack and frame. */ + stw %rp, -20(%sp) + ldo 64(%sp), %sp + stw %sp, -4(%sp) + stw %r19, -32(%sp) + + /* argc and argv should be in 25 and 24 (2nd and 3rd argument) */ + /* void (*rtld_fini) (void) (6th argument) */ + stw %r23, -56(%sp) + + /* Need to setup 1, 4, 5, and 7th arguments */ + +#ifdef PIC + /* Load $global$ address into %dp */ + bl .+8, %dp + addil L'$global$-$PIC_pcrel$0+1, %dp + ldo R'$global$-$PIC_pcrel$0+5(%r1), %dp + + /* load main (1st argument) */ + addil LT'.Lpmain, %r19 + ldw RT'.Lpmain(%r1), %r26 + ldw 0(%r26),%r26 + /* void (*init) (void) (4th argument) */ + addil LT'.Lp__libc_csu_init, %r19 + ldw RT'.Lp__libc_csu_init(%r1), %r23 + ldw 0(%r23), %r23 + /* void (*fini) (void) (5th argument) */ + addil LT'.Lp__libc_csu_fini, %r19 + ldw RT'.Lp__libc_csu_fini(%r1), %r22 + ldw 0(%r22), %r22 +#else + /* Load $global$ address into %dp */ + ldil L%$global$, %dp + ldo R%$global$(%dp), %dp + + /* load main (1st argument) */ + ldil LR'.Lpmain, %r26 + ldw RR'.Lpmain(%r26), %r26 + /* void (*init) (void) (4th argument) */ + ldil LR'.Lp__libc_csu_init, %r23 + ldw RR'.Lp__libc_csu_init(%r23), %r23 + /* void (*fini) (void) (5th argument) */ + ldil LR'.Lp__libc_csu_fini, %r22 + ldw RR'.Lp__libc_csu_fini(%r22), %r22 +#endif + /* Store 5th argument */ + stw %r22, -52(%sp) + /* void *stack_end (7th argument) */ + stw %sp, -60(%sp) + bl __libc_start_main,%r2 + nop + /* die horribly if it returned (it shouldn't) */ + iitlbp %r0,(%sr0,%r0) + nop + + .procend + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/i386/start-2.33.S b/zig/lib/libc/glibc/sysdeps/i386/start-2.33.S new file mode 100644 index 0000000000..c57b25f055 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/i386/start-2.33.S @@ -0,0 +1,151 @@ +/* Startup code compliant to the ELF i386 ABI. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This is the canonical entry point, usually the first thing in the text + segment. The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry + point runs, most registers' values are unspecified, except for: + + %edx Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + %esp The stack contains the arguments and environment: + 0(%esp) argc + 4(%esp) argv[0] + ... + (4*argc)(%esp) NULL + (4*(argc+1))(%esp) envp[0] + ... + NULL +*/ + +#include + +ENTRY (_start) + /* Clearing frame pointer is insufficient, use CFI. */ + cfi_undefined (eip) + /* Clear the frame pointer. The ABI suggests this be done, to mark + the outermost frame obviously. */ + xorl %ebp, %ebp + + /* Extract the arguments as encoded on the stack and set up + the arguments for `main': argc, argv. envp will be determined + later in __libc_start_main. */ + popl %esi /* Pop the argument count. */ + movl %esp, %ecx /* argv starts just at the current stack top.*/ + + /* Before pushing the arguments align the stack to a 16-byte + (SSE needs 16-byte alignment) boundary to avoid penalties from + misaligned accesses. Thanks to Edward Seidl + for pointing this out. */ + andl $0xfffffff0, %esp + pushl %eax /* Push garbage because we allocate + 28 more bytes. */ + + /* Provide the highest stack address to the user code (for stacks + which grow downwards). */ + pushl %esp + + pushl %edx /* Push address of the shared library + termination function. */ + +#ifdef PIC + /* Load PIC register. */ + call 1f + addl $_GLOBAL_OFFSET_TABLE_, %ebx + + /* Push address of our own entry points to .fini and .init. */ + leal __libc_csu_fini@GOTOFF(%ebx), %eax + pushl %eax + leal __libc_csu_init@GOTOFF(%ebx), %eax + pushl %eax + + pushl %ecx /* Push second argument: argv. */ + pushl %esi /* Push first argument: argc. */ + +# ifdef SHARED + pushl main@GOT(%ebx) +# else + /* Avoid relocation in static PIE since _start is called before + it is relocated. Don't use "leal main@GOTOFF(%ebx), %eax" + since main may be in a shared object. Linker will convert + "movl main@GOT(%ebx), %eax" to "leal main@GOTOFF(%ebx), %eax" + if main is defined locally. */ + movl main@GOT(%ebx), %eax + pushl %eax +# endif + + /* Call the user's main function, and exit with its value. + But let the libc call main. */ + call __libc_start_main@PLT +#else + /* Push address of our own entry points to .fini and .init. */ + pushl $__libc_csu_fini + pushl $__libc_csu_init + + pushl %ecx /* Push second argument: argv. */ + pushl %esi /* Push first argument: argc. */ + + pushl $main + + /* Call the user's main function, and exit with its value. + But let the libc call main. */ + call __libc_start_main +#endif + + hlt /* Crash if somehow `exit' does return. */ + +#ifdef PIC +1: movl (%esp), %ebx + ret +#endif +END (_start) + +/* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so + meaningless since we don't support machines < 80386. */ + .section .rodata + .globl _fp_hw +_fp_hw: .long 3 + .size _fp_hw, 4 + .type _fp_hw,@object + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/ia64/start-2.33.S b/zig/lib/libc/glibc/sysdeps/ia64/start-2.33.S new file mode 100644 index 0000000000..18c8962b6e --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/ia64/start-2.33.S @@ -0,0 +1,118 @@ +/* Copyright (C) 1999-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jes Sorensen, , April 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +/* + * Arguments for __libc_start_main: + * out0: main + * out1: argc + * out2: argv + * out3: init + * out4: fini + * out5: rtld_fini + * out6: stack_end + */ + + .align 32 + .global _start + + .proc _start + .type _start,@function +_start: + .prologue + .save rp, r0 + .body + .prologue + { .mlx + alloc r2 = ar.pfs,0,0,7,0 + movl r3 = FPSR_DEFAULT + } + { .mlx + adds out2 = 16, sp /* get address of argc value */ + movl gp = @gprel(0f) + ;; + } +0: { .mmi + ld8 out1 = [out2], 8 /* load argc and move out2 to become argv */ + mov.m r10 = ar.bsp /* fetch rbs base address */ + mov r9 = ip + ;; + } + { .mii + mov ar.fpsr = r3 + sub gp = r9, gp /* back-compute gp value */ + adds out6 = 16, sp /* highest non-environment stack address */ + ;; + } + { + addl r11 = @ltoff(__libc_ia64_register_backing_store_base), gp + addl out0 = @ltoff(@fptr(main)), gp + addl out3 = @ltoff(@fptr(__libc_csu_init)), gp + ;; + } + { .mmi + ld8 r3 = [r11] /* pointer to __libc_ia64_register_backing_store_base */ + ld8 out0 = [out0] /* pointer to `main' function descriptor */ + addl out4 = @ltoff(@fptr(__libc_csu_fini)), gp + ;; + } + { .mmi + ld8 out3 = [out3] /* pointer to `init' function descriptor */ + ld8 out4 = [out4] /* pointer to `fini' function descriptor */ + nop 0 + } + .body + { .mib + st8 [r3] = r10 + mov out5 = ret0 /* dynamic linker destructor */ + br.call.sptk.few rp = __libc_start_main + } + { .mib + break 0 /* break miserably if we ever return */ + } + .endp _start + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start + + .common __libc_ia64_register_backing_store_base, 8, 8 diff --git a/zig/lib/libc/glibc/sysdeps/m68k/start-2.33.S b/zig/lib/libc/glibc/sysdeps/m68k/start-2.33.S new file mode 100644 index 0000000000..f69a6502e6 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/m68k/start-2.33.S @@ -0,0 +1,120 @@ +/* Startup code compliant to the ELF m68k ABI. + Copyright (C) 1996-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +/* This is the canonical entry point, usually the first thing in the text + segment. The SVR4/m68k ABI says that when the entry point runs, + most registers' values are unspecified, except for: + + %a1 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + %sp The stack contains the arguments and environment: + 0(%sp) argc + 4(%sp) argv[0] + ... + (4*argc)(%sp) NULL + (4*(argc+1))(%sp) envp[0] + ... + NULL +*/ + +#include + + .text + .globl _start + .type _start,@function +_start: + /* Clear the frame pointer. The ABI suggests this be done, to mark + the outermost frame obviously. */ + sub.l %fp, %fp + + /* Extract the arguments as encoded on the stack and set up the + arguments for `main': argc, argv. envp will be determined + later in __libc_start_main. */ + move.l (%sp)+, %d0 /* Pop the argument count. */ + move.l %sp, %a0 /* The argument vector starts just at the + current stack top. */ + + /* Provide the highest stack address to the user code (for stacks + which grow downward). */ + pea (%sp) + + pea (%a1) /* Push address of the shared library + termination function. */ + +#ifdef PIC + /* Load PIC register. */ + LOAD_GOT (%a5) + + /* Push the address of our own entry points to `.fini' and + `.init'. */ + move.l __libc_csu_fini@GOT(%a5), -(%sp) + move.l __libc_csu_init@GOT(%a5), -(%sp) + + pea (%a0) /* Push second argument: argv. */ + move.l %d0, -(%sp) /* Push first argument: argc. */ + + move.l main@GOT(%a5), -(%sp) + + /* Call the user's main function, and exit with its value. But + let the libc call main. */ + jbsr __libc_start_main@PLTPC +#else + /* Push the address of our own entry points to `.fini' and + `.init'. */ + pea __libc_csu_fini + pea __libc_csu_init + + pea (%a0) /* Push second argument: argv. */ + move.l %d0, -(%sp) /* Push first argument: argc. */ + + pea main + + /* Call the user's main function, and exit with its value. But + let the libc call main. */ + jbsr __libc_start_main +#endif + + illegal /* Crash if somehow `exit' does return. */ + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/microblaze/start-2.33.S b/zig/lib/libc/glibc/sysdeps/microblaze/start-2.33.S new file mode 100644 index 0000000000..55d15d6308 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/microblaze/start-2.33.S @@ -0,0 +1,84 @@ +/* Copyright (C) 1995-2020 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + + .text + .globl _start + .type _start,@function +_start: + /* On entry the stack contains the following args: + r1+0 - argc + r1+4 - argv[0] + ... + r1+4*(argc-1) - argv[argc-1] + r1+4*argc - NULL + r1+4*argc + 4 - envp[0] + ... + NULL + */ + addk r3,r0,r0 + addk r5,r1,r0 +1: + addik r5,r5,4 + lw r4,r5,r0 + bneid r4,1b + addik r3,r3,1 + addik r6,r3,-1 + sw r6,r1,r0 + addik r7,r1,4 + addik r1,r1,-24 +#ifdef SHARED + /* Setup PIC. */ + mfs r20,rpc + addik r20,r20,_GLOBAL_OFFSET_TABLE_+8 + lwi r5,r20,main@GOT + lwi r8,r20,__libc_csu_init@GOT + lwi r9,r20,__libc_csu_fini@GOT + brid __libc_start_main@PLT + addk r10,r0,r0 +#else + addik r5,r0,main + addik r8,r0,__libc_csu_init + addik r9,r0,__libc_csu_fini + brid __libc_start_main + addk r10,r0,r0 +#endif + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/mips/start-2.33.S b/zig/lib/libc/glibc/sysdeps/mips/start-2.33.S new file mode 100644 index 0000000000..fabc8080df --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/mips/start-2.33.S @@ -0,0 +1,185 @@ +/* Startup code compliant to the ELF Mips ABI. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#define __ASSEMBLY__ 1 +#include +#include +#include + +#ifndef ENTRY_POINT +#error ENTRY_POINT needs to be defined for start.S on MIPS/ELF. +#endif + +/* This is the canonical entry point, usually the first thing in the text + segment. The SVR4/Mips ABI (pages 3-31, 3-32) says that when the entry + point runs, most registers' values are unspecified, except for: + + v0 ($2) Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + sp ($29) The stack contains the arguments and environment: + 0(%esp) argc + 4(%esp) argv[0] + ... + (4*argc)(%esp) NULL + (4*(argc+1))(%esp) envp[0] + ... + NULL + ra ($31) The return address register is set to zero so that programs + that search backword through stack frames recognize the last + stack frame. +*/ + + +/* We need to call: + __libc_start_main (int (*main) (int, char **, char **), int argc, + char **argv, void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void *stack_end) +*/ + + .text + .globl ENTRY_POINT + .type ENTRY_POINT,@function +#ifndef __mips16 +ENTRY_POINT: +# ifdef __PIC__ + SETUP_GPX($0) + SETUP_GPX64($25,$0) +# else + PTR_LA $28, _gp /* Setup GP correctly if we're non-PIC. */ + move $31, $0 +# endif + + PTR_LA $4, main /* main */ + PTR_L $5, 0($29) /* argc */ + PTR_ADDIU $6, $29, PTRSIZE /* argv */ + + /* Allocate space on the stack for seven arguments (o32 only) + and make sure the stack is aligned to double words (8 bytes) + on o32 and quad words (16 bytes) on n32 and n64. */ + + and $29, -2 * SZREG +# if _MIPS_SIM == _ABIO32 + PTR_SUBIU $29, 32 +# endif + PTR_LA $7, __libc_csu_init /* init */ + PTR_LA $8, __libc_csu_fini +# if _MIPS_SIM == _ABIO32 + PTR_S $8, 16($29) /* fini */ + PTR_S $2, 20($29) /* rtld_fini */ + PTR_S $29, 24($29) /* stack_end */ +# else + move $9, $2 /* rtld_fini */ + move $10, $29 /* stack_end */ +# endif + PTR_LA $25, __libc_start_main + jalr $25 +hlt: b hlt /* Crash if somehow it does return. */ + +#elif _MIPS_SIM == _ABIO32 /* __mips16 */ + /* MIPS16 entry point. */ + .set mips16 +ENTRY_POINT: +# ifdef __PIC__ + li $3, %hi(_gp_disp) + addiu $4, $pc, %lo(_gp_disp) + sll $3, 16 + addu $3, $4 + move $gp, $3 +# else + li $3, %hi(_gp) + sll $3, 16 + addiu $3, %lo(_gp) + move $gp, $3 +# endif + /* Tie end of stack frames. */ + li $4, 0 + move $31, $4 + /* Create new SP value in $7, including alignment. */ + li $4, 2 * SZREG + neg $4, $4 + move $7, $sp + and $7, $4 + addiu $7, -32 + /* Load arguments with original SP. */ + lw $5, 0($sp) + addiu $6, $sp, PTRSIZE + /* Update SP. */ + move $sp, $7 + /* Lay out last arguments, and call __libc_start_main(). */ +# ifdef __PIC__ + sw $7, 24($sp) /* stack_end */ + lw $4, %got(__libc_csu_fini)($3) + lw $7, %got(__libc_csu_init)($3) /* init */ + sw $4, 16($sp) /* fini */ + lw $4, %got(main)($3) /* main */ + lw $3, %call16(__libc_start_main)($3) + sw $2, 20($sp) /* rtld_fini */ + move $25, $3 + jalr $3 +# else + lw $4, 1f + sw $7, 24($sp) /* stack_end */ + lw $7, 2f /* init */ + sw $4, 16($sp) /* fini */ + lw $4, 3f /* main */ + sw $2, 20($sp) /* rtld_fini */ + /* Load and call __libc_start_main(). */ + lw $3, 4f + jalr $3 +# endif +hlt: b hlt /* Crash if somehow it does return. */ +# ifndef __PIC__ + .align 2 +1: .word __libc_csu_fini +2: .word __libc_csu_init +3: .word main +4: .word __libc_start_main +# endif + +#else /* __mips16 && _MIPS_SIM != _ABIO32 */ +# error "MIPS16 support for N32/N64 not implemented" + +#endif /* __mips16 */ + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/powerpc/powerpc32/start-2.33.S b/zig/lib/libc/glibc/sysdeps/powerpc/powerpc32/start-2.33.S new file mode 100644 index 0000000000..b7b9a133a2 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/powerpc/powerpc32/start-2.33.S @@ -0,0 +1,95 @@ +/* Startup code for programs linked with GNU libc. + Copyright (C) 1998-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* We do not want .eh_frame info for crt1.o since crt1.o is linked + before crtbegin.o, the file defining __EH_FRAME_BEGIN__. */ +#undef cfi_startproc +#define cfi_startproc +#undef cfi_endproc +#define cfi_endproc + + /* These are the various addresses we require. */ +#ifdef PIC + .section ".data" +#else + .section ".rodata" +#endif + .align 2 +L(start_addresses): + .long _SDA_BASE_ + .long main + .long __libc_csu_init + .long __libc_csu_fini + ASM_SIZE_DIRECTIVE(L(start_addresses)) + + .section ".text" +ENTRY(_start) + /* Save the stack pointer, in case we're statically linked under Linux. */ + mr r9,r1 + /* Set up an initial stack frame, and clear the LR. */ + clrrwi r1,r1,4 +#ifdef PIC + SETUP_GOT_ACCESS(r13,got_label) + li r0,0 +#else + li r0,0 +#endif + stwu r1,-16(r1) + mtlr r0 + stw r0,0(r1) + /* Set r13 to point at the 'small data area', and put the address of + start_addresses in r8. Also load the GOT pointer so that new PLT + calls work, like the one to __libc_start_main. */ +#ifdef PIC + addis r30,r13,_GLOBAL_OFFSET_TABLE_-got_label@ha + addis r8,r13,L(start_addresses)-got_label@ha + addi r30,r30,_GLOBAL_OFFSET_TABLE_-got_label@l + lwzu r13, L(start_addresses)-got_label@l(r8) +#else + lis r8,L(start_addresses)@ha + lwzu r13,L(start_addresses)@l(r8) +#endif + /* and continue in libc-start, in glibc. */ + b JUMPTARGET(__libc_start_main) +END(_start) + +/* Define a symbol for the first piece of initialized data. */ + .section ".data" + .globl __data_start +__data_start: + .long 0 +weak_alias (__data_start, data_start) diff --git a/zig/lib/libc/glibc/sysdeps/powerpc/powerpc64/start-2.33.S b/zig/lib/libc/glibc/sysdeps/powerpc/powerpc64/start-2.33.S new file mode 100644 index 0000000000..94bf771e83 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/powerpc/powerpc64/start-2.33.S @@ -0,0 +1,92 @@ +/* Startup code for programs linked with GNU libc. PowerPC64 version. + Copyright (C) 1998-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* We do not want .eh_frame info for crt1.o since crt1.o is linked + before crtbegin.o, the file defining __EH_FRAME_BEGIN__. */ +#undef cfi_startproc +#define cfi_startproc +#undef cfi_endproc +#define cfi_endproc + + /* These are the various addresses we require. */ +#ifdef PIC + .section ".data.rel.ro.local","aw" +#else + .section ".rodata" +#endif + .align 3 +L(start_addresses): + .quad 0 /* was _SDA_BASE_ but not in 64-bit ABI*/ +/* function descriptors so don't need JUMPTARGET */ + .quad main + .quad __libc_csu_init + .quad __libc_csu_fini + + ASM_SIZE_DIRECTIVE(L(start_addresses)) + + .section ".toc","aw" +.L01: + .tc L(start_addresses)[TC],L(start_addresses) + .section ".text" +ENTRY (_start) + /* Save the stack pointer, in case we're statically linked under Linux. */ + mr r9,r1 + /* Set up an initial stack frame, and clear the LR. */ + clrrdi r1,r1,4 + li r0,0 + stdu r1,-128(r1) + mtlr r0 + std r0,0(r1) + + /* put the address of start_addresses in r8... ** +** PPC64 ABI uses R13 for thread local, so we leave it alone */ + ld r8,.L01@toc(r2) + + /* and continue in libc-start, in glibc. */ + b JUMPTARGET(__libc_start_main) +/* Older versions of ld need this nop to recognize that it's OK to call via a + TOC adjusting stub. */ + nop + +END(_start) + +/* Define a symbol for the first piece of initialized data. */ + .section ".data" + .globl __data_start +__data_start: + .long 0 +weak_alias (__data_start, data_start) diff --git a/zig/lib/libc/glibc/sysdeps/riscv/start-2.33.S b/zig/lib/libc/glibc/sysdeps/riscv/start-2.33.S new file mode 100644 index 0000000000..09511b1ef8 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/riscv/start-2.33.S @@ -0,0 +1,86 @@ +/* Startup code compliant to the ELF RISC-V ABI. + Copyright (C) 1995-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#define __ASSEMBLY__ 1 +#include +#include +#include + +/* The entry point's job is to call __libc_start_main. Per the ABI, + a0 contains the address of a function to be passed to atexit. + __libc_start_main wants this in a5. */ + +ENTRY (ENTRY_POINT) + /* Terminate call stack by noting ra is undefined. Use a dummy + .cfi_label to force starting the FDE. */ + .cfi_label .Ldummy + cfi_undefined (ra) + call load_gp + mv a5, a0 /* rtld_fini. */ + /* main may be in a shared library. */ + la a0, main + REG_L a1, 0(sp) /* argc. */ + addi a2, sp, SZREG /* argv. */ + andi sp, sp, ALMASK /* Align stack. */ + lla a3, __libc_csu_init + lla a4, __libc_csu_fini + mv a6, sp /* stack_end. */ + + call __libc_start_main@plt + ebreak +END (ENTRY_POINT) + +/* Dynamic links need the global pointer to be initialized prior to calling + any shared library's initializers, so we use preinit_array to load it. + This doesn't cut it for static links, though, since the global pointer + needs to be initialized before calling __libc_start_main in that case. + So we redundantly initialize it at the beginning of _start. */ + +load_gp: +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + ret + + .section .preinit_array,"aw" + .dc.a load_gp + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/s390/s390-32/start-2.33.S b/zig/lib/libc/glibc/sysdeps/s390/s390-32/start-2.33.S new file mode 100644 index 0000000000..af9dccfb9d --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/s390/s390-32/start-2.33.S @@ -0,0 +1,218 @@ +/* Startup code compliant to the ELF s390 ABI. + Copyright (C) 2000-2020 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* + This is the canonical entry point, usually the first thing in the text + segment. Most registers' values are unspecified, except for: + + %r14 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + %r15 The stack contains the arguments and environment: + 0(%r15) argc + 4(%r15) argv[0] + ... + (4*argc)(%r15) NULL + (4*(argc+1))(%r15) envp[0] + ... + NULL +*/ + + .text + .globl _start + .type _start,@function +_start: + cfi_startproc + /* Mark r14 as undefined in order to stop unwinding here! */ + cfi_undefined (r14) + + /* Check if the kernel provides highgprs facility if needed by + the binary. */ + + lr %r6,%r15 + la %r6,4(%r6) /* Skip the argument counter. */ + +.L11: l %r5,0(%r6) /* Skip the argument vector. */ + la %r6,4(%r6) + ltr %r5,%r5 + jne .L11 + +.L12: l %r5,0(%r6) /* Skip the environment vector. */ + la %r6,4(%r6) + ltr %r5,%r5 + jne .L12 + + /* Usually the auxiliary vector can be expected directly after + the environment variables. But we have to skip extra zeros + because the loader might have removed unsecure variables for + setuid programs. */ + +.L26: l %r5,0(%r6) + la %r6,4(%r6) + ltr %r5,%r5 + jz .L26 + + ahi %r6,-4 + + /* Obtain the needed values from the auxiliary vector. */ + + lhi %r7,16 /* AT_HWCAP */ + lhi %r8,3 /* AT_PHDR */ + lhi %r9,5 /* AT_PHNUM */ + lhi %r2,4 /* AT_PHENT */ +.L13: l %r5,0(%r6) + clr %r5,%r7 + jne .L15 + l %r10,4(%r6) /* r10 = AT_HWCAP value. */ +.L15: clr %r5,%r8 + jne .L16 + l %r11,4(%r6) /* r11 = AT_PHDR value. */ +.L16: clr %r5,%r9 + jne .L17 + l %r12,4(%r6) /* r12 = AT_PHNUM value. */ +.L17: clr %r5,%r2 + jne .L18 + l %r0,4(%r6) /* r0 = AT_PHENT value. */ +.L18: ltr %r5,%r5 + la %r6,8(%r6) + jnz .L13 + + /* Locate the ELF header by looking for the first PT_LOAD + segment with a p_offset of zero. */ + + lr %r4,%r11 /* Backup AT_PHDR. */ + lhi %r7,1 /* PT_LOAD id */ + lhi %r8,0 +.L19: cl %r7,0(%r4) /* p_type == PT_LOAD? */ + jne .L20 + cl %r8,4(%r4) /* p_offset == 0? */ + jne .L20 + l %r9,8(%r4) /* r9 = PT_LOAD.p_vaddr <- ELF header address */ + j .L24 +.L20: alr %r4,%r0 /* r4 += AT_PHENT value */ + brct %r12,.L19 + + j .+2 /* Trap, there must be such a phdr. */ + +.L24: lr %r4,%r11 /* Backup AT_PHDR. */ + lhi %r2,6 /* PT_PHDR id */ +.L23: cl %r2,0(%r4) + jne .L22 + l %r3,8(%r4) /* r3 = PT_PHDR p_vaddr */ + j .L25 +.L22: alr %r4,%r0 /* r4 += AT_PHENT value */ + brct %r12,.L23 + + j .L14 /* No PT_PHDR found - skip checking. */ + +.L25: slr %r11,%r3 /* AT_PHDR - PT_PHDR.p_vaddr (relocation offset)*/ + alr %r9,%r11 /* PT_LOAD.p_vaddr += relocation offset */ + + l %r5,36(%r9) /* Load the e_flags field. */ + tml %r5,1 + jz .L14 /* Binary does not require highgprs facility. */ + + tml %r10,512 /* Check the AT_HWCAP value. */ + jz 2 /* Trap if no highgprs facility available. */ +.L14: + + /* Setup pointer to literal pool of _start */ + basr %r13,0 +.L0: ahi %r13,.Llit-.L0 + + /* load argc and argv from stack */ + la %r4,4(%r15) # get argv + l %r3,0(%r15) # get argc + + /* align the stack to a double word boundary */ + lhi %r0,-8 + nr %r15,%r0 + + /* Setup a stack frame and a parameter area */ + ahi %r15,-104 # make room on stack + xc 0(4,%r15),0(%r15) # clear back-chain + + /* set up arguments for __libc_start_main: + main, argc, argv, envp, _init, _fini, rtld_fini, stack_end + Note that envp will be determined later in __libc_start_main + */ + stm %r14,%r15,96(%r15) # store rtld_fini/stack_end to parameter area + la %r7,96(%r15) + l %r6,.L2-.Llit(%r13) # load pointer to __libc_csu_fini + l %r5,.L1-.Llit(%r13) # load pointer to __libc_csu_init + l %r2,.L3-.Llit(%r13) # load pointer to main + l %r1,.L4-.Llit(%r13) # load pointer to __libc_start_main +#ifdef PIC + l %r12,.L5-.Llit(%r13) # load .got pointer + la %r6,0(%r13,%r6) + la %r5,0(%r13,%r5) + la %r12,0(%r13,%r12) + l %r2,0(%r12,%r2) + la %r1,0(%r13,%r1) +#endif + + /* ok, now branch to the libc main routine */ + basr %r14,%r1 + + /* crash if __libc_start_main returns */ + .word 0 + + cfi_endproc +.Llit: +#ifndef PIC +.L1: .long __libc_csu_init +.L2: .long __libc_csu_fini +.L3: .long main +.L4: .long __libc_start_main +#else +.L1: .long __libc_csu_init-.Llit +.L2: .long __libc_csu_fini-.Llit +.L3: .long main@GOT +.L4: .long __libc_start_main@plt-.Llit +.L5: .long _GLOBAL_OFFSET_TABLE_-.Llit +#endif + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/s390/s390-64/start-2.33.S b/zig/lib/libc/glibc/sysdeps/s390/s390-64/start-2.33.S new file mode 100644 index 0000000000..02ed4aad51 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/s390/s390-64/start-2.33.S @@ -0,0 +1,107 @@ +/* Startup code compliant to the 64 bit S/390 ELF ABI. + Copyright (C) 2001-2020 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* + This is the canonical entry point, usually the first thing in the text + segment. Most registers' values are unspecified, except for: + + %r14 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + %r15 The stack contains the arguments and environment: + 0(%r15) argc + 8(%r15) argv[0] + ... + (8*argc)(%r15) NULL + (8*(argc+1))(%r15) envp[0] + ... + NULL +*/ + + .text + .globl _start + .type _start,@function +_start: + cfi_startproc + /* Mark r14 as undefined in order to stop unwinding here! */ + cfi_undefined (r14) + /* Load argc and argv from stack. */ + la %r4,8(%r15) # get argv + lg %r3,0(%r15) # get argc + + /* Align the stack to a double word boundary. */ + lghi %r0,-16 + ngr %r15,%r0 + + /* Setup a stack frame and a parameter area. */ + aghi %r15,-176 # make room on stack + xc 0(8,%r15),0(%r15) # clear back-chain + + /* Set up arguments for __libc_start_main: + main, argc, argv, envp, _init, _fini, rtld_fini, stack_end + Note that envp will be determined later in __libc_start_main. + */ + stmg %r14,%r15,160(%r15) # store rtld_fini/stack_end to parameter area + la %r7,160(%r15) + larl %r6,__libc_csu_fini # load pointer to __libc_csu_fini + larl %r5,__libc_csu_init # load pointer to __libc_csu_init + + /* Ok, now branch to the libc main routine. */ +#ifdef PIC + larl %r2,main@GOTENT # load pointer to main + lg %r2,0(%r2) + brasl %r14,__libc_start_main@plt +#else + larl %r2,main # load pointer to main + brasl %r14,__libc_start_main +#endif + + /* Crash if __libc_start_main returns. */ + .word 0 + + cfi_endproc + + /* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/glibc/sysdeps/sh/start-2.33.S b/zig/lib/libc/glibc/sysdeps/sh/start-2.33.S new file mode 100644 index 0000000000..433f67a259 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/sh/start-2.33.S @@ -0,0 +1,111 @@ +/* Startup code for SH & ELF. + Copyright (C) 1999-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This is the canonical entry point, usually the first thing in the text + segment. + + Note that the code in the .init section has already been run. + This includes _init and _libc_init + + + At this entry point, most registers' values are unspecified, except: + + r4 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + sp The stack contains the arguments and environment: + 0(sp) argc + 4(sp) argv[0] + ... + (4*argc)(sp) NULL + (4*(argc+1))(sp) envp[0] + ... + NULL +*/ + + .text + .globl _start + .type _start,@function +_start: + /* Clear the frame pointer since this is the outermost frame. */ + mov #0, r14 + + /* Pop argc off the stack and save a pointer to argv */ + mov.l @r15+,r5 + mov r15, r6 + + /* Push the last arguments to main() onto the stack */ + mov.l r4,@-r15 + mov.l L_fini,r0 + mov.l r0,@-r15 + + /* Set up the other arguments for main() that go in registers */ + mov.l L_main,r4 + mov.l L_init,r7 + + /* __libc_start_main (main, argc, argv, init, fini, rtld_fini) */ + + /* Let the libc call main and exit with its return code. */ + mov.l L_libc_start_main,r1 + jsr @r1 + nop + /* should never get here....*/ + mov.l L_abort,r1 + jsr @r1 + nop + .align 2 +L_main: + .long main +L_init: + .long __libc_csu_init +L_fini: + .long __libc_csu_fini +L_libc_start_main: + .long __libc_start_main +L_abort: + .long abort +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start + .global __fpscr_values +__fpscr_values: + .long 0 + .long 0x80000 diff --git a/zig/lib/libc/glibc/sysdeps/sparc/sparc32/start-2.33.S b/zig/lib/libc/glibc/sysdeps/sparc/sparc32/start-2.33.S new file mode 100644 index 0000000000..5afc3f6e89 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/sparc/sparc32/start-2.33.S @@ -0,0 +1,99 @@ +/* Startup code for elf32-sparc + Copyright (C) 1997-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + + + .section ".text" + .align 4 + .global _start + .type _start,#function +_start: +#ifdef PIC + SETUP_PIC_REG(l7) +#endif + + /* Terminate the stack frame, and reserve space for functions to + drop their arguments. */ + mov %g0, %fp + sub %sp, 6*4, %sp + + /* Extract the arguments and environment as encoded on the stack. The + argument info starts after one register window (16 words) past the SP. */ + ld [%sp+22*4], %o1 + add %sp, 23*4, %o2 + + /* Load the addresses of the user entry points. */ +#ifndef PIC + sethi %hi(main), %o0 + sethi %hi(__libc_csu_init), %o3 + sethi %hi(__libc_csu_fini), %o4 + or %o0, %lo(main), %o0 + or %o3, %lo(__libc_csu_init), %o3 + or %o4, %lo(__libc_csu_fini), %o4 +#else + sethi %gdop_hix22(main), %o0 + sethi %gdop_hix22(__libc_csu_init), %o3 + sethi %gdop_hix22(__libc_csu_fini), %o4 + xor %o0, %gdop_lox10(main), %o0 + xor %o3, %gdop_lox10(__libc_csu_init), %o3 + xor %o4, %gdop_lox10(__libc_csu_fini), %o4 + ld [%l7 + %o0], %o0, %gdop(main) + ld [%l7 + %o3], %o3, %gdop(__libc_csu_init) + ld [%l7 + %o4], %o4, %gdop(__libc_csu_fini) +#endif + + /* When starting a binary via the dynamic linker, %g1 contains the + address of the shared library termination function, which will be + registered with atexit(). If we are statically linked, this will + be NULL. */ + mov %g1, %o5 + + /* Let libc do the rest of the initialization, and call main. */ + call __libc_start_main + nop + + /* Die very horribly if exit returns. */ + unimp + + .size _start, .-_start + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 +weak_alias (__data_start, data_start) diff --git a/zig/lib/libc/glibc/sysdeps/sparc/sparc64/start-2.33.S b/zig/lib/libc/glibc/sysdeps/sparc/sparc64/start-2.33.S new file mode 100644 index 0000000000..8167a3363d --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/sparc/sparc64/start-2.33.S @@ -0,0 +1,100 @@ +/* Startup code for elf64-sparc + Copyright (C) 1997-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + + + .section ".text" + .align 4 + .global _start + .type _start,#function +_start: +#ifdef PIC + SETUP_PIC_REG(l7) +#endif + + /* Terminate the stack frame, and reserve space for functions to + drop their arguments. */ + mov %g0, %fp + sub %sp, 6*8, %sp + + /* Extract the arguments and environment as encoded on the stack. The + argument info starts after one register window (16 words) past the SP, + plus the bias we added, plus the magic v9 STACK_BIAS. */ + ldx [%sp+STACK_BIAS+22*8], %o1 + add %sp, STACK_BIAS+23*8, %o2 + + /* Load the addresses of the user entry points. */ +#ifndef PIC + sethi %hi(main), %o0 + sethi %hi(__libc_csu_init), %o3 + sethi %hi(__libc_csu_fini), %o4 + or %o0, %lo(main), %o0 + or %o3, %lo(__libc_csu_init), %o3 + or %o4, %lo(__libc_csu_fini), %o4 +#else + sethi %gdop_hix22(main), %o0 + sethi %gdop_hix22(__libc_csu_init), %o3 + sethi %gdop_hix22(__libc_csu_fini), %o4 + xor %o0, %gdop_lox10(main), %o0 + xor %o3, %gdop_lox10(__libc_csu_init), %o3 + xor %o4, %gdop_lox10(__libc_csu_fini), %o4 + ldx [%l7 + %o0], %o0, %gdop(main) + ldx [%l7 + %o3], %o3, %gdop(__libc_csu_init) + ldx [%l7 + %o4], %o4, %gdop(__libc_csu_fini) +#endif + + /* When starting a binary via the dynamic linker, %g1 contains the + address of the shared library termination function, which will be + registered with atexit(). If we are statically linked, this will + be NULL. */ + mov %g1, %o5 + + /* Let libc do the rest of the initialization, and call main. */ + call __libc_start_main + nop + + /* Die very horribly if exit returns. */ + illtrap 0 + + .size _start, .-_start + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 +weak_alias (__data_start, data_start) diff --git a/zig/lib/libc/glibc/sysdeps/x86_64/start-2.33.S b/zig/lib/libc/glibc/sysdeps/x86_64/start-2.33.S new file mode 100644 index 0000000000..7477b632f7 --- /dev/null +++ b/zig/lib/libc/glibc/sysdeps/x86_64/start-2.33.S @@ -0,0 +1,131 @@ +/* Startup code compliant to the ELF x86-64 ABI. + Copyright (C) 2001-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Jaeger , 2001. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This is the canonical entry point, usually the first thing in the text + segment. The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry + point runs, most registers' values are unspecified, except for: + + %rdx Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + %rsp The stack contains the arguments and environment: + 0(%rsp) argc + LP_SIZE(%rsp) argv[0] + ... + (LP_SIZE*argc)(%rsp) NULL + (LP_SIZE*(argc+1))(%rsp) envp[0] + ... + NULL +*/ + +#include + +ENTRY (_start) + /* Clearing frame pointer is insufficient, use CFI. */ + cfi_undefined (rip) + /* Clear the frame pointer. The ABI suggests this be done, to mark + the outermost frame obviously. */ + xorl %ebp, %ebp + + /* Extract the arguments as encoded on the stack and set up + the arguments for __libc_start_main (int (*main) (int, char **, char **), + int argc, char *argv, + void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void *stack_end). + The arguments are passed via registers and on the stack: + main: %rdi + argc: %rsi + argv: %rdx + init: %rcx + fini: %r8 + rtld_fini: %r9 + stack_end: stack. */ + + mov %RDX_LP, %R9_LP /* Address of the shared library termination + function. */ +#ifdef __ILP32__ + mov (%rsp), %esi /* Simulate popping 4-byte argument count. */ + add $4, %esp +#else + popq %rsi /* Pop the argument count. */ +#endif + /* argv starts just at the current stack top. */ + mov %RSP_LP, %RDX_LP + /* Align the stack to a 16 byte boundary to follow the ABI. */ + and $~15, %RSP_LP + + /* Push garbage because we push 8 more bytes. */ + pushq %rax + + /* Provide the highest stack address to the user code (for stacks + which grow downwards). */ + pushq %rsp + +#ifdef PIC + /* Pass address of our own entry points to .fini and .init. */ + mov __libc_csu_fini@GOTPCREL(%rip), %R8_LP + mov __libc_csu_init@GOTPCREL(%rip), %RCX_LP + + mov main@GOTPCREL(%rip), %RDI_LP +#else + /* Pass address of our own entry points to .fini and .init. */ + mov $__libc_csu_fini, %R8_LP + mov $__libc_csu_init, %RCX_LP + + mov $main, %RDI_LP +#endif + + /* Call the user's main function, and exit with its value. + But let the libc call main. Since __libc_start_main in + libc.so is called very early, lazy binding isn't relevant + here. Use indirect branch via GOT to avoid extra branch + to PLT slot. In case of static executable, ld in binutils + 2.26 or above can convert indirect branch into direct + branch. */ + call *__libc_start_main@GOTPCREL(%rip) + + hlt /* Crash if somehow `exit' does return. */ +END (_start) + +/* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/zig/lib/libc/include/arm64-linux-any/asm/auxvec.h b/zig/lib/libc/include/aarch64-linux-any/asm/auxvec.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/auxvec.h rename to zig/lib/libc/include/aarch64-linux-any/asm/auxvec.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/bitsperlong.h b/zig/lib/libc/include/aarch64-linux-any/asm/bitsperlong.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/bitsperlong.h rename to zig/lib/libc/include/aarch64-linux-any/asm/bitsperlong.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/bpf_perf_event.h b/zig/lib/libc/include/aarch64-linux-any/asm/bpf_perf_event.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/bpf_perf_event.h rename to zig/lib/libc/include/aarch64-linux-any/asm/bpf_perf_event.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/byteorder.h b/zig/lib/libc/include/aarch64-linux-any/asm/byteorder.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/byteorder.h rename to zig/lib/libc/include/aarch64-linux-any/asm/byteorder.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/fcntl.h b/zig/lib/libc/include/aarch64-linux-any/asm/fcntl.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/fcntl.h rename to zig/lib/libc/include/aarch64-linux-any/asm/fcntl.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/hwcap.h b/zig/lib/libc/include/aarch64-linux-any/asm/hwcap.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/hwcap.h rename to zig/lib/libc/include/aarch64-linux-any/asm/hwcap.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/kvm.h b/zig/lib/libc/include/aarch64-linux-any/asm/kvm.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/kvm.h rename to zig/lib/libc/include/aarch64-linux-any/asm/kvm.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/mman.h b/zig/lib/libc/include/aarch64-linux-any/asm/mman.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/mman.h rename to zig/lib/libc/include/aarch64-linux-any/asm/mman.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/param.h b/zig/lib/libc/include/aarch64-linux-any/asm/param.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/param.h rename to zig/lib/libc/include/aarch64-linux-any/asm/param.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/perf_regs.h b/zig/lib/libc/include/aarch64-linux-any/asm/perf_regs.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/perf_regs.h rename to zig/lib/libc/include/aarch64-linux-any/asm/perf_regs.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/posix_types.h b/zig/lib/libc/include/aarch64-linux-any/asm/posix_types.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/posix_types.h rename to zig/lib/libc/include/aarch64-linux-any/asm/posix_types.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/ptrace.h b/zig/lib/libc/include/aarch64-linux-any/asm/ptrace.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/ptrace.h rename to zig/lib/libc/include/aarch64-linux-any/asm/ptrace.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/setup.h b/zig/lib/libc/include/aarch64-linux-any/asm/setup.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/setup.h rename to zig/lib/libc/include/aarch64-linux-any/asm/setup.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/sigcontext.h b/zig/lib/libc/include/aarch64-linux-any/asm/sigcontext.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/sigcontext.h rename to zig/lib/libc/include/aarch64-linux-any/asm/sigcontext.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/signal.h b/zig/lib/libc/include/aarch64-linux-any/asm/signal.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/signal.h rename to zig/lib/libc/include/aarch64-linux-any/asm/signal.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/statfs.h b/zig/lib/libc/include/aarch64-linux-any/asm/statfs.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/statfs.h rename to zig/lib/libc/include/aarch64-linux-any/asm/statfs.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/sve_context.h b/zig/lib/libc/include/aarch64-linux-any/asm/sve_context.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/sve_context.h rename to zig/lib/libc/include/aarch64-linux-any/asm/sve_context.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/ucontext.h b/zig/lib/libc/include/aarch64-linux-any/asm/ucontext.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/ucontext.h rename to zig/lib/libc/include/aarch64-linux-any/asm/ucontext.h diff --git a/zig/lib/libc/include/arm64-linux-any/asm/unistd.h b/zig/lib/libc/include/aarch64-linux-any/asm/unistd.h similarity index 100% rename from zig/lib/libc/include/arm64-linux-any/asm/unistd.h rename to zig/lib/libc/include/aarch64-linux-any/asm/unistd.h diff --git a/zig/lib/libc/include/any-linux-any/asm-generic/poll.h b/zig/lib/libc/include/any-linux-any/asm-generic/poll.h index 5a056d94fb..e46fb2b83e 100644 --- a/zig/lib/libc/include/any-linux-any/asm-generic/poll.h +++ b/zig/lib/libc/include/any-linux-any/asm-generic/poll.h @@ -29,7 +29,7 @@ #define POLLRDHUP 0x2000 #endif -#define POLLFREE (__poll_t)0x4000 /* currently only for epoll */ +#define POLLFREE (__poll_t)0x4000 #define POLL_BUSY_LOOP (__poll_t)0x8000 diff --git a/zig/lib/libc/include/any-linux-any/drm/virtgpu_drm.h b/zig/lib/libc/include/any-linux-any/drm/virtgpu_drm.h index dbfc2d8e8f..3e6c78ce82 100644 --- a/zig/lib/libc/include/any-linux-any/drm/virtgpu_drm.h +++ b/zig/lib/libc/include/any-linux-any/drm/virtgpu_drm.h @@ -196,6 +196,13 @@ struct drm_virtgpu_context_init { __u64 ctx_set_params; }; +/* + * Event code that's given when VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK is in + * effect. The event size is sizeof(drm_event), since there is no additional + * payload. + */ +#define VIRTGPU_EVENT_FENCE_SIGNALED 0x90000000 + #define DRM_IOCTL_VIRTGPU_MAP \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map) diff --git a/zig/lib/libc/include/any-linux-any/linux/byteorder/big_endian.h b/zig/lib/libc/include/any-linux-any/linux/byteorder/big_endian.h index 5a2871c649..66d4f0c344 100644 --- a/zig/lib/libc/include/any-linux-any/linux/byteorder/big_endian.h +++ b/zig/lib/libc/include/any-linux-any/linux/byteorder/big_endian.h @@ -9,6 +9,7 @@ #define __BIG_ENDIAN_BITFIELD #endif +#include #include #include diff --git a/zig/lib/libc/include/any-linux-any/linux/byteorder/little_endian.h b/zig/lib/libc/include/any-linux-any/linux/byteorder/little_endian.h index 981bfec681..5959febbc5 100644 --- a/zig/lib/libc/include/any-linux-any/linux/byteorder/little_endian.h +++ b/zig/lib/libc/include/any-linux-any/linux/byteorder/little_endian.h @@ -9,6 +9,7 @@ #define __LITTLE_ENDIAN_BITFIELD #endif +#include #include #include diff --git a/zig/lib/libc/include/any-linux-any/linux/if_ether.h b/zig/lib/libc/include/any-linux-any/linux/if_ether.h index d7069f0e5e..53b8462712 100644 --- a/zig/lib/libc/include/any-linux-any/linux/if_ether.h +++ b/zig/lib/libc/include/any-linux-any/linux/if_ether.h @@ -117,7 +117,7 @@ #define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */ #define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */ -#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value +#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is more than this value * then the frame is Ethernet II. Else it is 802.3 */ /* diff --git a/zig/lib/libc/include/any-linux-any/linux/mptcp.h b/zig/lib/libc/include/any-linux-any/linux/mptcp.h index d58014aa18..d146c9a3e9 100644 --- a/zig/lib/libc/include/any-linux-any/linux/mptcp.h +++ b/zig/lib/libc/include/any-linux-any/linux/mptcp.h @@ -134,19 +134,21 @@ struct mptcp_info { * MPTCP_EVENT_REMOVED: token, rem_id * An address has been lost by the peer. * - * MPTCP_EVENT_SUB_ESTABLISHED: token, family, saddr4 | saddr6, - * daddr4 | daddr6, sport, dport, backup, - * if_idx [, error] + * MPTCP_EVENT_SUB_ESTABLISHED: token, family, loc_id, rem_id, + * saddr4 | saddr6, daddr4 | daddr6, sport, + * dport, backup, if_idx [, error] * A new subflow has been established. 'error' should not be set. * - * MPTCP_EVENT_SUB_CLOSED: token, family, saddr4 | saddr6, daddr4 | daddr6, - * sport, dport, backup, if_idx [, error] + * MPTCP_EVENT_SUB_CLOSED: token, family, loc_id, rem_id, saddr4 | saddr6, + * daddr4 | daddr6, sport, dport, backup, if_idx + * [, error] * A subflow has been closed. An error (copy of sk_err) could be set if an * error has been detected for this subflow. * - * MPTCP_EVENT_SUB_PRIORITY: token, family, saddr4 | saddr6, daddr4 | daddr6, - * sport, dport, backup, if_idx [, error] - * The priority of a subflow has changed. 'error' should not be set. + * MPTCP_EVENT_SUB_PRIORITY: token, family, loc_id, rem_id, saddr4 | saddr6, + * daddr4 | daddr6, sport, dport, backup, if_idx + * [, error] + * The priority of a subflow has changed. 'error' should not be set. */ enum mptcp_event_type { MPTCP_EVENT_UNSPEC = 0, diff --git a/zig/lib/libc/include/any-linux-any/linux/nfc.h b/zig/lib/libc/include/any-linux-any/linux/nfc.h index 2ed487942c..15dee8a25a 100644 --- a/zig/lib/libc/include/any-linux-any/linux/nfc.h +++ b/zig/lib/libc/include/any-linux-any/linux/nfc.h @@ -263,7 +263,7 @@ enum nfc_sdp_attr { #define NFC_SE_ENABLED 0x1 struct sockaddr_nfc { - sa_family_t sa_family; + __kernel_sa_family_t sa_family; __u32 dev_idx; __u32 target_idx; __u32 nfc_protocol; @@ -271,14 +271,14 @@ struct sockaddr_nfc { #define NFC_LLCP_MAX_SERVICE_NAME 63 struct sockaddr_nfc_llcp { - sa_family_t sa_family; + __kernel_sa_family_t sa_family; __u32 dev_idx; __u32 target_idx; __u32 nfc_protocol; __u8 dsap; /* Destination SAP, if known */ __u8 ssap; /* Source SAP to be bound to */ char service_name[NFC_LLCP_MAX_SERVICE_NAME]; /* Service name URI */; - size_t service_name_len; + __kernel_size_t service_name_len; }; /* NFC socket protocols */ diff --git a/zig/lib/libc/include/any-linux-any/linux/resource.h b/zig/lib/libc/include/any-linux-any/linux/resource.h index fa597fbb25..99d1815c09 100644 --- a/zig/lib/libc/include/any-linux-any/linux/resource.h +++ b/zig/lib/libc/include/any-linux-any/linux/resource.h @@ -66,10 +66,17 @@ struct rlimit64 { #define _STK_LIM (8*1024*1024) /* - * GPG2 wants 64kB of mlocked memory, to make sure pass phrases - * and other sensitive information are never written to disk. + * Limit the amount of locked memory by some sane default: + * root can always increase this limit if needed. + * + * The main use-cases are (1) preventing sensitive memory + * from being swapped; (2) real-time operations; (3) via + * IOURING_REGISTER_BUFFERS. + * + * The first two don't need much. The latter will take as + * much as it can get. 8MB is a reasonably sane default. */ -#define MLOCK_LIMIT ((PAGE_SIZE > 64*1024) ? PAGE_SIZE : 64*1024) +#define MLOCK_LIMIT (8*1024*1024) /* * Due to binary compatibility, the actual resource numbers diff --git a/zig/lib/libc/include/any-linux-any/linux/version.h b/zig/lib/libc/include/any-linux-any/linux/version.h index 43e0b8295b..118d1d84fc 100644 --- a/zig/lib/libc/include/any-linux-any/linux/version.h +++ b/zig/lib/libc/include/any-linux-any/linux/version.h @@ -1,5 +1,5 @@ -#define LINUX_VERSION_CODE 331776 +#define LINUX_VERSION_CODE 331778 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c))) #define LINUX_VERSION_MAJOR 5 #define LINUX_VERSION_PATCHLEVEL 16 -#define LINUX_VERSION_SUBLEVEL 0 \ No newline at end of file +#define LINUX_VERSION_SUBLEVEL 2 \ No newline at end of file diff --git a/zig/lib/libc/include/generic-glibc/features.h b/zig/lib/libc/include/generic-glibc/features.h index 62ffeace4b..dba3fc8491 100644 --- a/zig/lib/libc/include/generic-glibc/features.h +++ b/zig/lib/libc/include/generic-glibc/features.h @@ -220,8 +220,12 @@ # define _DEFAULT_SOURCE 1 # undef _ATFILE_SOURCE # define _ATFILE_SOURCE 1 + +# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 34) || __GLIBC__ > 2 # undef _DYNAMIC_STACK_SIZE_SOURCE # define _DYNAMIC_STACK_SIZE_SOURCE 1 +# endif + #endif /* If nothing (other than _GNU_SOURCE and _DEFAULT_SOURCE) is defined, @@ -477,7 +481,7 @@ /* Major and minor version number of the GNU C library package. Use these macros to test for features in specific releases. */ #define __GLIBC__ 2 -#define __GLIBC_MINOR__ 34 +/* Zig patch: we pass `-D__GLIBC_MINOR__=XX` depending on the target. */ #define __GLIBC_PREREQ(maj, min) \ ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min)) @@ -512,4 +516,4 @@ #include -#endif /* features.h */ \ No newline at end of file +#endif /* features.h */ diff --git a/zig/lib/std/Thread.zig b/zig/lib/std/Thread.zig index f2203e2808..8a5929b592 100644 --- a/zig/lib/std/Thread.zig +++ b/zig/lib/std/Thread.zig @@ -16,6 +16,7 @@ pub const StaticResetEvent = @import("Thread/StaticResetEvent.zig"); pub const Mutex = @import("Thread/Mutex.zig"); pub const Semaphore = @import("Thread/Semaphore.zig"); pub const Condition = @import("Thread/Condition.zig"); +pub const RwLock = @import("Thread/RwLock.zig"); pub const use_pthreads = target.os.tag != .windows and target.os.tag != .wasi and builtin.link_libc; const is_gnu = target.abi.isGnu(); @@ -1151,3 +1152,27 @@ test "Thread.detach" { event.wait(); try std.testing.expectEqual(value, 1); } + +fn testWaitForSignal(mutex: *Mutex, cond: *Condition) void { + mutex.lock(); + defer mutex.unlock(); + cond.signal(); + cond.wait(mutex); +} + +test "Condition.signal" { + if (builtin.single_threaded) return error.SkipZigTest; + + var mutex = Mutex{}; + var cond = Condition{}; + + var thread: Thread = undefined; + { + mutex.lock(); + defer mutex.unlock(); + thread = try Thread.spawn(.{}, testWaitForSignal, .{ &mutex, &cond }); + cond.wait(&mutex); + cond.signal(); + } + thread.join(); +} diff --git a/zig/lib/std/Thread/Condition.zig b/zig/lib/std/Thread/Condition.zig index 615f68cd9b..848e17ddce 100644 --- a/zig/lib/std/Thread/Condition.zig +++ b/zig/lib/std/Thread/Condition.zig @@ -106,7 +106,7 @@ pub const AtomicCondition = struct { .linux => { switch (linux.getErrno(linux.futex_wait( &cond.futex, - linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_WAIT, + linux.FUTEX.PRIVATE_FLAG | linux.FUTEX.WAIT, 0, null, ))) { @@ -128,7 +128,7 @@ pub const AtomicCondition = struct { .linux => { switch (linux.getErrno(linux.futex_wake( &cond.futex, - linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_WAKE, + linux.FUTEX.PRIVATE_FLAG | linux.FUTEX.WAKE, 1, ))) { .SUCCESS => {}, diff --git a/zig/lib/std/Thread/RwLock.zig b/zig/lib/std/Thread/RwLock.zig index cfe06c76e8..6cce7d1217 100644 --- a/zig/lib/std/Thread/RwLock.zig +++ b/zig/lib/std/Thread/RwLock.zig @@ -3,15 +3,12 @@ //! This API requires being initialized at runtime, and initialization //! can fail. Once initialized, the core operations cannot fail. -impl: Impl, +impl: Impl = .{}, const RwLock = @This(); const std = @import("../std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; -const Mutex = std.Thread.Mutex; -const Semaphore = std.Semaphore; -const CondVar = std.CondVar; pub const Impl = if (builtin.single_threaded) SingleThreadedRwLock @@ -20,14 +17,6 @@ else if (std.Thread.use_pthreads) else DefaultRwLock; -pub fn init(rwl: *RwLock) void { - return rwl.impl.init(); -} - -pub fn deinit(rwl: *RwLock) void { - return rwl.impl.deinit(); -} - /// Attempts to obtain exclusive lock ownership. /// Returns `true` if the lock is obtained, `false` otherwise. pub fn tryLock(rwl: *RwLock) bool { @@ -64,20 +53,8 @@ pub fn unlockShared(rwl: *RwLock) void { /// Single-threaded applications use this for deadlock checks in /// debug mode, and no-ops in release modes. pub const SingleThreadedRwLock = struct { - state: enum { unlocked, locked_exclusive, locked_shared }, - shared_count: usize, - - pub fn init(rwl: *SingleThreadedRwLock) void { - rwl.* = .{ - .state = .unlocked, - .shared_count = 0, - }; - } - - pub fn deinit(rwl: *SingleThreadedRwLock) void { - assert(rwl.state == .unlocked); - assert(rwl.shared_count == 0); - } + state: enum { unlocked, locked_exclusive, locked_shared } = .unlocked, + shared_count: usize = 0, /// Attempts to obtain exclusive lock ownership. /// Returns `true` if the lock is obtained, `false` otherwise. @@ -152,55 +129,41 @@ pub const SingleThreadedRwLock = struct { }; pub const PthreadRwLock = struct { - rwlock: pthread_rwlock_t, - - pub fn init(rwl: *PthreadRwLock) void { - rwl.* = .{ .rwlock = .{} }; - } - - pub fn deinit(rwl: *PthreadRwLock) void { - const safe_rc: std.os.E = switch (builtin.os.tag) { - .dragonfly, .netbsd => .AGAIN, - else => .SUCCESS, - }; - const rc = std.c.pthread_rwlock_destroy(&rwl.rwlock); - assert(rc == .SUCCESS or rc == safe_rc); - rwl.* = undefined; - } + rwlock: std.c.pthread_rwlock_t = .{}, pub fn tryLock(rwl: *PthreadRwLock) bool { - return pthread_rwlock_trywrlock(&rwl.rwlock) == .SUCCESS; + return std.c.pthread_rwlock_trywrlock(&rwl.rwlock) == .SUCCESS; } pub fn lock(rwl: *PthreadRwLock) void { - const rc = pthread_rwlock_wrlock(&rwl.rwlock); + const rc = std.c.pthread_rwlock_wrlock(&rwl.rwlock); assert(rc == .SUCCESS); } pub fn unlock(rwl: *PthreadRwLock) void { - const rc = pthread_rwlock_unlock(&rwl.rwlock); + const rc = std.c.pthread_rwlock_unlock(&rwl.rwlock); assert(rc == .SUCCESS); } pub fn tryLockShared(rwl: *PthreadRwLock) bool { - return pthread_rwlock_tryrdlock(&rwl.rwlock) == .SUCCESS; + return std.c.pthread_rwlock_tryrdlock(&rwl.rwlock) == .SUCCESS; } pub fn lockShared(rwl: *PthreadRwLock) void { - const rc = pthread_rwlock_rdlock(&rwl.rwlock); + const rc = std.c.pthread_rwlock_rdlock(&rwl.rwlock); assert(rc == .SUCCESS); } pub fn unlockShared(rwl: *PthreadRwLock) void { - const rc = pthread_rwlock_unlock(&rwl.rwlock); + const rc = std.c.pthread_rwlock_unlock(&rwl.rwlock); assert(rc == .SUCCESS); } }; pub const DefaultRwLock = struct { - state: usize, - mutex: Mutex, - semaphore: Semaphore, + state: usize = 0, + mutex: std.Thread.Mutex = .{}, + semaphore: std.Thread.Semaphore = .{}, const IS_WRITING: usize = 1; const WRITER: usize = 1 << 1; @@ -209,20 +172,6 @@ pub const DefaultRwLock = struct { const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER); const Count = std.meta.Int(.unsigned, @divFloor(std.meta.bitCount(usize) - 1, 2)); - pub fn init(rwl: *DefaultRwLock) void { - rwl.* = .{ - .state = 0, - .mutex = Mutex.init(), - .semaphore = Semaphore.init(0), - }; - } - - pub fn deinit(rwl: *DefaultRwLock) void { - rwl.semaphore.deinit(); - rwl.mutex.deinit(); - rwl.* = undefined; - } - pub fn tryLock(rwl: *DefaultRwLock) bool { if (rwl.mutex.tryLock()) { const state = @atomicLoad(usize, &rwl.state, .SeqCst); diff --git a/zig/lib/std/build.zig b/zig/lib/std/build.zig index b7785b214f..8eda542d6e 100644 --- a/zig/lib/std/build.zig +++ b/zig/lib/std/build.zig @@ -1552,6 +1552,8 @@ pub const LibExeObjStep = struct { subsystem: ?std.Target.SubSystem = null, + entry_symbol_name: ?[]const u8 = null, + /// Overrides the default stack size stack_size: ?u64 = null, @@ -2253,6 +2255,11 @@ pub const LibExeObjStep = struct { try zig_args.append(@tagName(builder.color)); } + if (self.entry_symbol_name) |entry| { + try zig_args.append("--entry"); + try zig_args.append(entry); + } + if (self.stack_size) |stack_size| { try zig_args.append("--stack"); try zig_args.append(try std.fmt.allocPrint(builder.allocator, "{}", .{stack_size})); @@ -2651,6 +2658,8 @@ pub const LibExeObjStep = struct { try zig_args.append(bin_name); try zig_args.append("--test-cmd"); try zig_args.append("--dir=."); + try zig_args.append("--test-cmd"); + try zig_args.append("--allow-unknown-exports"); // TODO: Remove when stage2 is default compiler try zig_args.append("--test-cmd-bin"); } else { try zig_args.append("--test-no-exec"); diff --git a/zig/lib/std/c.zig b/zig/lib/std/c.zig index 9203232e6b..ed9ceada00 100644 --- a/zig/lib/std/c.zig +++ b/zig/lib/std/c.zig @@ -357,6 +357,8 @@ pub extern "c" fn openlog(ident: [*:0]const u8, logopt: c_int, facility: c_int) pub extern "c" fn closelog() void; pub extern "c" fn setlogmask(maskpri: c_int) c_int; +pub extern "c" fn if_nametoindex([*:0]const u8) c_int; + pub const max_align_t = if (builtin.abi == .msvc) f64 else if (builtin.target.isDarwin()) diff --git a/zig/lib/std/c/darwin.zig b/zig/lib/std/c/darwin.zig index bfb805c36c..f4ca9cd6dd 100644 --- a/zig/lib/std/c/darwin.zig +++ b/zig/lib/std/c/darwin.zig @@ -6,6 +6,26 @@ const native_arch = builtin.target.cpu.arch; const maxInt = std.math.maxInt; const iovec_const = std.os.iovec_const; +const arch_bits = switch (native_arch) { + .aarch64 => @import("darwin/aarch64.zig"), + .x86_64 => @import("darwin/x86_64.zig"), + else => struct {}, +}; + +pub const ucontext_t = extern struct { + onstack: c_int, + sigmask: sigset_t, + stack: stack_t, + link: ?*ucontext_t, + mcsize: u64, + mcontext: *mcontext_t, +}; + +pub const mcontext_t = extern struct { + es: arch_bits.exception_state, + ss: arch_bits.thread_state, +}; + extern "c" fn __error() *c_int; pub extern "c" fn NSVersionOfRunTimeLibrary(library_name: [*:0]const u8) u32; pub extern "c" fn _NSGetExecutablePath(buf: [*:0]u8, bufsize: *u32) c_int; @@ -108,6 +128,8 @@ pub fn sigaddset(set: *sigset_t, signo: u5) void { pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; +pub const IFNAMESIZE = 16; + pub const AI = struct { /// get address to use bind() pub const PASSIVE = 0x00000001; diff --git a/zig/lib/std/c/darwin/aarch64.zig b/zig/lib/std/c/darwin/aarch64.zig new file mode 100644 index 0000000000..70153b5dfb --- /dev/null +++ b/zig/lib/std/c/darwin/aarch64.zig @@ -0,0 +1,18 @@ +// See C headers in +// lib/libc/include/aarch64-macos.12-gnu/mach/arm/_structs.h + +pub const exception_state = extern struct { + far: u64, // Virtual Fault Address + esr: u32, // Exception syndrome + exception: u32, // Number of arm exception taken +}; + +pub const thread_state = extern struct { + regs: [29]u64, // General purpose registers + fp: u64, // Frame pointer x29 + lr: u64, // Link register x30 + sp: u64, // Stack pointer x31 + pc: u64, // Program counter + cpsr: u32, // Current program status register + __pad: u32, +}; diff --git a/zig/lib/std/c/darwin/x86_64.zig b/zig/lib/std/c/darwin/x86_64.zig new file mode 100644 index 0000000000..a7f2c509c7 --- /dev/null +++ b/zig/lib/std/c/darwin/x86_64.zig @@ -0,0 +1,30 @@ +pub const exception_state = extern struct { + trapno: u16, + cpu: u16, + err: u32, + faultvaddr: u64, +}; + +pub const thread_state = extern struct { + rax: u64, + rbx: u64, + rcx: u64, + rdx: u64, + rdi: u64, + rsi: u64, + rbp: u64, + rsp: u64, + r8: u64, + r9: u64, + r10: u64, + r11: u64, + r12: u64, + r13: u64, + r14: u64, + r15: u64, + rip: u64, + rflags: u64, + cs: u64, + fs: u64, + gs: u64, +}; diff --git a/zig/lib/std/c/linux.zig b/zig/lib/std/c/linux.zig index c5047ef318..db55b5d850 100644 --- a/zig/lib/std/c/linux.zig +++ b/zig/lib/std/c/linux.zig @@ -56,6 +56,7 @@ pub const STDOUT_FILENO = linux.STDOUT_FILENO; pub const SYS = linux.SYS; pub const Sigaction = linux.Sigaction; pub const TCP = linux.TCP; +pub const TCSA = linux.TCSA; pub const VDSO = linux.VDSO; pub const W = linux.W; pub const W_OK = linux.W_OK; @@ -85,11 +86,13 @@ pub const pollfd = linux.pollfd; pub const rlim_t = linux.rlim_t; pub const rlimit = linux.rlimit; pub const rlimit_resource = linux.rlimit_resource; +pub const rusage = linux.rusage; pub const siginfo_t = linux.siginfo_t; pub const sigset_t = linux.sigset_t; pub const sockaddr = linux.sockaddr; pub const socklen_t = linux.socklen_t; pub const stack_t = linux.stack_t; +pub const tcflag_t = linux.tcflag_t; pub const termios = linux.termios; pub const time_t = linux.time_t; pub const timespec = linux.timespec; diff --git a/zig/lib/std/c/openbsd.zig b/zig/lib/std/c/openbsd.zig index 4a41545e3f..6ba11e8e5a 100644 --- a/zig/lib/std/c/openbsd.zig +++ b/zig/lib/std/c/openbsd.zig @@ -703,8 +703,48 @@ pub const T = struct { pub const IOCXMTFRAME = 0x80087444; }; +// BSD Authentication +pub const auth_item_t = c_int; + +pub const AUTHV = struct { + pub const ALL: auth_item_t = 0; + pub const CHALLENGE: auth_item_t = 1; + pub const CLASS: auth_item_t = 2; + pub const NAME: auth_item_t = 3; + pub const SERVICE: auth_item_t = 4; + pub const STYLE: auth_item_t = 5; + pub const INTERACTIVE: auth_item_t = 6; +}; + +pub const BI = struct { + pub const AUTH = "authorize"; // Accepted authentication + pub const REJECT = "reject"; // Rejected authentication + pub const CHALLENGE = "reject challenge"; // Reject with a challenge + pub const SILENT = "reject silent"; // Reject silently + pub const REMOVE = "remove"; // remove file on error + pub const ROOTOKAY = "authorize root"; // root authenticated + pub const SECURE = "authorize secure"; // okay on non-secure line + pub const SETENV = "setenv"; // set environment variable + pub const UNSETENV = "unsetenv"; // unset environment variable + pub const VALUE = "value"; // set local variable + pub const EXPIRED = "reject expired"; // account expired + pub const PWEXPIRED = "reject pwexpired"; // password expired + pub const FDPASS = "fd"; // child is passing an fd +}; + +pub const AUTH = struct { + pub const OKAY: c_int = 0x01; // user authenticated + pub const ROOTOKAY: c_int = 0x02; // authenticated as root + pub const SECURE: c_int = 0x04; // secure login + pub const SILENT: c_int = 0x08; // silent rejection + pub const CHALLENGE: c_int = 0x10; // a challenge was given + pub const EXPIRED: c_int = 0x20; // account expired + pub const PWEXPIRED: c_int = 0x40; // password expired + pub const ALLOW: c_int = (OKAY | ROOTOKAY | SECURE); +}; + // Term -const V = struct { +pub const V = struct { pub const EOF = 0; // ICANON pub const EOL = 1; // ICANON pub const EOL2 = 2; // ICANON @@ -942,7 +982,7 @@ comptime { std.debug.assert(@sizeOf(siginfo_t) == 136); } -const arch_bits = switch (builtin.cpu.arch) { +pub usingnamespace switch (builtin.cpu.arch) { .x86_64 => struct { pub const ucontext_t = extern struct { sc_rdi: c_long, @@ -972,7 +1012,7 @@ const arch_bits = switch (builtin.cpu.arch) { sc_rsp: c_long, sc_ss: c_long, - sc_fpstate: arch_bits.fxsave64, + sc_fpstate: fxsave64, __sc_unused: c_int, sc_mask: c_int, sc_cookie: c_long, @@ -995,8 +1035,6 @@ const arch_bits = switch (builtin.cpu.arch) { }, else => struct {}, }; -pub const ucontext_t = arch_bits.ucontext_t; -pub const fxsave64 = arch_bits.fxsave64; pub const sigset_t = c_uint; pub const empty_sigset: sigset_t = 0; diff --git a/zig/lib/std/child_process.zig b/zig/lib/std/child_process.zig index 7808dcd1e5..ace58ecf4f 100644 --- a/zig/lib/std/child_process.zig +++ b/zig/lib/std/child_process.zig @@ -252,6 +252,35 @@ pub const ChildProcess = struct { } } + const WindowsAsyncReadResult = enum { + pending, + closed, + full, + }; + + fn windowsAsyncRead( + handle: windows.HANDLE, + overlapped: *windows.OVERLAPPED, + buf: *std.ArrayList(u8), + bump_amt: usize, + max_output_bytes: usize, + ) !WindowsAsyncReadResult { + while (true) { + const new_capacity = std.math.min(buf.items.len + bump_amt, max_output_bytes); + try buf.ensureTotalCapacity(new_capacity); + const next_buf = buf.unusedCapacitySlice(); + if (next_buf.len == 0) return .full; + var read_bytes: u32 = undefined; + const read_result = windows.kernel32.ReadFile(handle, next_buf.ptr, math.cast(u32, next_buf.len) catch maxInt(u32), &read_bytes, overlapped); + if (read_result == 0) return switch (windows.kernel32.GetLastError()) { + .IO_PENDING => .pending, + .BROKEN_PIPE => .closed, + else => |err| windows.unexpectedError(err), + }; + buf.items.len += read_bytes; + } + } + fn collectOutputWindows(child: *const ChildProcess, outs: [2]*std.ArrayList(u8), max_output_bytes: usize) !void { const bump_amt = 512; const handles = [_]windows.HANDLE{ @@ -274,15 +303,17 @@ pub const ChildProcess = struct { // Windows Async IO requires an initial call to ReadFile before waiting on the handle for ([_]u1{ 0, 1 }) |i| { - const new_capacity = std.math.min(outs[i].items.len + bump_amt, max_output_bytes); - try outs[i].ensureTotalCapacity(new_capacity); - const buf = outs[i].unusedCapacitySlice(); - _ = windows.kernel32.ReadFile(handles[i], buf.ptr, math.cast(u32, buf.len) catch maxInt(u32), null, &overlapped[i]); - wait_objects[wait_object_count] = handles[i]; - wait_object_count += 1; + switch (try windowsAsyncRead(handles[i], &overlapped[i], outs[i], bump_amt, max_output_bytes)) { + .pending => { + wait_objects[wait_object_count] = handles[i]; + wait_object_count += 1; + }, + .closed => {}, // don't add to the wait_objects list + .full => return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong, + } } - while (true) { + while (wait_object_count > 0) { const status = windows.kernel32.WaitForMultipleObjects(wait_object_count, &wait_objects, 0, windows.INFINITE); if (status == windows.WAIT_FAILED) { switch (windows.kernel32.GetLastError()) { @@ -306,23 +337,21 @@ pub const ChildProcess = struct { var read_bytes: u32 = undefined; if (windows.kernel32.GetOverlappedResult(handles[i], &overlapped[i], &read_bytes, 0) == 0) { switch (windows.kernel32.GetLastError()) { - .BROKEN_PIPE => { - if (wait_object_count == 0) - break; - continue; - }, + .BROKEN_PIPE => continue, else => |err| return windows.unexpectedError(err), } } outs[i].items.len += read_bytes; - const new_capacity = std.math.min(outs[i].items.len + bump_amt, max_output_bytes); - try outs[i].ensureTotalCapacity(new_capacity); - const buf = outs[i].unusedCapacitySlice(); - if (buf.len == 0) return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong; - _ = windows.kernel32.ReadFile(handles[i], buf.ptr, math.cast(u32, buf.len) catch maxInt(u32), null, &overlapped[i]); - wait_objects[wait_object_count] = handles[i]; - wait_object_count += 1; + + switch (try windowsAsyncRead(handles[i], &overlapped[i], outs[i], bump_amt, max_output_bytes)) { + .pending => { + wait_objects[wait_object_count] = handles[i]; + wait_object_count += 1; + }, + .closed => {}, // don't add to the wait_objects list + .full => return if (i == 0) error.StdoutStreamTooLong else error.StderrStreamTooLong, + } } } diff --git a/zig/lib/std/crypto.zig b/zig/lib/std/crypto.zig index 313cb7680f..b13ba000cf 100644 --- a/zig/lib/std/crypto.zig +++ b/zig/lib/std/crypto.zig @@ -158,7 +158,7 @@ pub const nacl = struct { pub const utils = @import("crypto/utils.zig"); /// This is a thread-local, cryptographically secure pseudo random number generator. -pub const random = &@import("crypto/tlcsprng.zig").interface; +pub const random = @import("crypto/tlcsprng.zig").interface; const std = @import("std.zig"); diff --git a/zig/lib/std/crypto/aes.zig b/zig/lib/std/crypto/aes.zig index 778cb80f8b..c969dfd0f7 100644 --- a/zig/lib/std/crypto/aes.zig +++ b/zig/lib/std/crypto/aes.zig @@ -126,12 +126,29 @@ test "expand 128-bit key" { } test "expand 256-bit key" { - const key = [_]u8{ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 }; + const key = [_]u8{ + 0x60, 0x3d, 0xeb, 0x10, + 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, + 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, + 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, + 0x09, 0x14, 0xdf, 0xf4, + }; const exp_enc = [_]*const [32:0]u8{ - "603deb1015ca71be2b73aef0857d7781", "1f352c073b6108d72d9810a30914dff4", "9ba354118e6925afa51a8b5f2067fcde", "a8b09c1a93d194cdbe49846eb75d5b9a", "d59aecb85bf3c917fee94248de8ebe96", "b5a9328a2678a647983122292f6c79b3", "812c81addadf48ba24360af2fab8b464", "98c5bfc9bebd198e268c3ba709e04214", "68007bacb2df331696e939e46c518d80", "c814e20476a9fb8a5025c02d59c58239", "de1369676ccc5a71fa2563959674ee15", "5886ca5d2e2f31d77e0af1fa27cf73c3", "749c47ab18501ddae2757e4f7401905a", "cafaaae3e4d59b349adf6acebd10190d", "fe4890d1e6188d0b046df344706c631e", + "603deb1015ca71be2b73aef0857d7781", "1f352c073b6108d72d9810a30914dff4", "9ba354118e6925afa51a8b5f2067fcde", + "a8b09c1a93d194cdbe49846eb75d5b9a", "d59aecb85bf3c917fee94248de8ebe96", "b5a9328a2678a647983122292f6c79b3", + "812c81addadf48ba24360af2fab8b464", "98c5bfc9bebd198e268c3ba709e04214", "68007bacb2df331696e939e46c518d80", + "c814e20476a9fb8a5025c02d59c58239", "de1369676ccc5a71fa2563959674ee15", "5886ca5d2e2f31d77e0af1fa27cf73c3", + "749c47ab18501ddae2757e4f7401905a", "cafaaae3e4d59b349adf6acebd10190d", "fe4890d1e6188d0b046df344706c631e", }; const exp_dec = [_]*const [32:0]u8{ - "fe4890d1e6188d0b046df344706c631e", "ada23f4963e23b2455427c8a5c709104", "57c96cf6074f07c0706abb07137f9241", "b668b621ce40046d36a047ae0932ed8e", "34ad1e4450866b367725bcc763152946", "32526c367828b24cf8e043c33f92aa20", "c440b289642b757227a3d7f114309581", "d669a7334a7ade7a80c8f18fc772e9e3", "25ba3c22a06bc7fb4388a28333934270", "54fb808b9c137949cab22ff547ba186c", "6c3d632985d1fbd9e3e36578701be0f3", "4a7459f9c8e8f9c256a156bc8d083799", "42107758e9ec98f066329ea193f8858b", "8ec6bff6829ca03b9e49af7edba96125", "603deb1015ca71be2b73aef0857d7781", + "fe4890d1e6188d0b046df344706c631e", "ada23f4963e23b2455427c8a5c709104", "57c96cf6074f07c0706abb07137f9241", + "b668b621ce40046d36a047ae0932ed8e", "34ad1e4450866b367725bcc763152946", "32526c367828b24cf8e043c33f92aa20", + "c440b289642b757227a3d7f114309581", "d669a7334a7ade7a80c8f18fc772e9e3", "25ba3c22a06bc7fb4388a28333934270", + "54fb808b9c137949cab22ff547ba186c", "6c3d632985d1fbd9e3e36578701be0f3", "4a7459f9c8e8f9c256a156bc8d083799", + "42107758e9ec98f066329ea193f8858b", "8ec6bff6829ca03b9e49af7edba96125", "603deb1015ca71be2b73aef0857d7781", }; const enc = Aes256.initEnc(key); const dec = Aes256.initDec(key); diff --git a/zig/lib/std/crypto/bcrypt.zig b/zig/lib/std/crypto/bcrypt.zig index bd3c9ca7d4..85584e17a7 100644 --- a/zig/lib/std/crypto/bcrypt.zig +++ b/zig/lib/std/crypto/bcrypt.zig @@ -26,12 +26,279 @@ pub const hash_length: usize = 60; const State = struct { sboxes: [4][256]u32 = [4][256]u32{ - .{ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a }, - .{ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 }, - .{ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 }, - .{ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 }, + .{ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, + }, + .{ + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, + }, + .{ + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, + }, + .{ + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, + }, + }, + subkeys: [18]u32 = [18]u32{ + 0x243f6a88, 0x85a308d3, 0x13198a2e, + 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, + 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, + 0xb5470917, 0x9216d5d9, 0x8979fb1b, }, - subkeys: [18]u32 = [18]u32{ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b }, fn toWord(data: []const u8, current: *usize) u32 { var t: u32 = 0; diff --git a/zig/lib/std/crypto/pcurves/p256/p256_64.zig b/zig/lib/std/crypto/pcurves/p256/p256_64.zig index 9d24bdc956..4ea8f268f3 100644 --- a/zig/lib/std/crypto/pcurves/p256/p256_64.zig +++ b/zig/lib/std/crypto/pcurves/p256/p256_64.zig @@ -13,7 +13,38 @@ // // Computed values: // eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) -// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// bytes_eval z = z[0] +// + (z[1] << 8) +// + (z[2] << 16) +// + (z[3] << 24) +// + (z[4] << 32) +// + (z[5] << 40) +// + (z[6] << 48) +// + (z[7] << 56) +// + (z[8] << 64) +// + (z[9] << 72) +// + (z[10] << 80) +// + (z[11] << 88) +// + (z[12] << 96) +// + (z[13] << 104) +// + (z[14] << 112) +// + (z[15] << 120) +// + (z[16] << 128) +// + (z[17] << 136) +// + (z[18] << 144) +// + (z[19] << 152) +// + (z[20] << 160) +// + (z[21] << 168) +// + (z[22] << 176) +// + (z[23] << 184) +// + (z[24] << 192) +// + (z[25] << 200) +// + (z[26] << 208) +// + (z[27] << 216) +// + (z[28] << 224) +// + (z[29] << 232) +// + (z[30] << 240) +// + (z[31] << 248) // twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in // if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 diff --git a/zig/lib/std/crypto/pcurves/p256/p256_scalar_64.zig b/zig/lib/std/crypto/pcurves/p256/p256_scalar_64.zig index c6c08b4c46..9c99d18ccf 100644 --- a/zig/lib/std/crypto/pcurves/p256/p256_scalar_64.zig +++ b/zig/lib/std/crypto/pcurves/p256/p256_scalar_64.zig @@ -13,7 +13,38 @@ // // Computed values: // eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) -// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// bytes_eval z = z[0] +// + (z[1] << 8) +// + (z[2] << 16) +// + (z[3] << 24) +// + (z[4] << 32) +// + (z[5] << 40) +// + (z[6] << 48) +// + (z[7] << 56) +// + (z[8] << 64) +// + (z[9] << 72) +// + (z[10] << 80) +// + (z[11] << 88) +// + (z[12] << 96) +// + (z[13] << 104) +// + (z[14] << 112) +// + (z[15] << 120) +// + (z[16] << 128) +// + (z[17] << 136) +// + (z[18] << 144) +// + (z[19] << 152) +// + (z[20] << 160) +// + (z[21] << 168) +// + (z[22] << 176) +// + (z[23] << 184) +// + (z[24] << 192) +// + (z[25] << 200) +// + (z[26] << 208) +// + (z[27] << 216) +// + (z[28] << 224) +// + (z[29] << 232) +// + (z[30] << 240) +// + (z[31] << 248) // twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in // if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 diff --git a/zig/lib/std/debug.zig b/zig/lib/std/debug.zig index 6c09b71451..135d2017e3 100644 --- a/zig/lib/std/debug.zig +++ b/zig/lib/std/debug.zig @@ -6,6 +6,7 @@ const io = std.io; const os = std.os; const fs = std.fs; const process = std.process; +const testing = std.testing; const elf = std.elf; const DW = std.dwarf; const macho = std.macho; @@ -559,7 +560,7 @@ pub const TTY = struct { fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol { var min: usize = 0; - var max: usize = symbols.len; + var max: usize = symbols.len - 1; while (min < max) { const mid = min + (max - min) / 2; const curr = &symbols[mid]; @@ -572,9 +573,36 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach return curr; } } + + const max_sym = &symbols[symbols.len - 1]; + if (address >= max_sym.address()) + return max_sym; + return null; } +test "machoSearchSymbols" { + const symbols = [_]MachoSymbol{ + .{ .addr = 100, .strx = undefined, .size = undefined, .ofile = undefined }, + .{ .addr = 200, .strx = undefined, .size = undefined, .ofile = undefined }, + .{ .addr = 300, .strx = undefined, .size = undefined, .ofile = undefined }, + }; + + try testing.expectEqual(@as(?*const MachoSymbol, null), machoSearchSymbols(&symbols, 0)); + try testing.expectEqual(@as(?*const MachoSymbol, null), machoSearchSymbols(&symbols, 99)); + try testing.expectEqual(&symbols[0], machoSearchSymbols(&symbols, 100).?); + try testing.expectEqual(&symbols[0], machoSearchSymbols(&symbols, 150).?); + try testing.expectEqual(&symbols[0], machoSearchSymbols(&symbols, 199).?); + + try testing.expectEqual(&symbols[1], machoSearchSymbols(&symbols, 200).?); + try testing.expectEqual(&symbols[1], machoSearchSymbols(&symbols, 250).?); + try testing.expectEqual(&symbols[1], machoSearchSymbols(&symbols, 299).?); + + try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 300).?); + try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 301).?); + try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?); +} + /// TODO resources https://github.com/ziglang/zig/issues/4353 pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void { const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { @@ -1573,8 +1601,13 @@ fn getDebugInfoAllocator() mem.Allocator { /// Whether or not the current target can print useful debug information when a segfault occurs. pub const have_segfault_handling_support = switch (native_os) { - .linux, .netbsd, .solaris => true, - .windows => true, + .linux, + .macos, + .netbsd, + .solaris, + .windows, + => true, + .freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"), else => false, }; @@ -1601,7 +1634,7 @@ pub fn attachSegfaultHandler() void { return; } var act = os.Sigaction{ - .handler = .{ .sigaction = handleSegfaultLinux }, + .handler = .{ .sigaction = handleSegfaultPosix }, .mask = os.empty_sigset, .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND), }; @@ -1629,7 +1662,7 @@ fn resetSegfaultHandler() void { os.sigaction(os.SIG.BUS, &act, null); } -fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn { +fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn { // Reset to the default handler so that if a segfault happens in this handler it will crash // the process. Also when this handler returns, the original instruction will be repeated // and the resulting segfault will crash the process rather than continually dump stack traces. @@ -1637,7 +1670,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any const addr = switch (native_os) { .linux => @ptrToInt(info.fields.sigfault.addr), - .freebsd => @ptrToInt(info.addr), + .freebsd, .macos => @ptrToInt(info.addr), .netbsd => @ptrToInt(info.info.reason.fault.addr), .openbsd => @ptrToInt(info.data.fault.addr), .solaris => @ptrToInt(info.reason.fault.addr), @@ -1668,12 +1701,14 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]), .freebsd => @intCast(usize, ctx.mcontext.rip), .openbsd => @intCast(usize, ctx.sc_rip), + .macos => @intCast(usize, ctx.mcontext.ss.rip), else => unreachable, }; const bp = switch (native_os) { .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]), .openbsd => @intCast(usize, ctx.sc_rbp), .freebsd => @intCast(usize, ctx.mcontext.rbp), + .macos => @intCast(usize, ctx.mcontext.ss.rbp), else => unreachable, }; dumpStackTraceFromBase(bp, ip); @@ -1686,9 +1721,15 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any }, .aarch64 => { const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); - const ip = @intCast(usize, ctx.mcontext.pc); + const ip = switch (native_os) { + .macos => @intCast(usize, ctx.mcontext.ss.pc), + else => @intCast(usize, ctx.mcontext.pc), + }; // x29 is the ABI-designated frame pointer - const bp = @intCast(usize, ctx.mcontext.regs[29]); + const bp = switch (native_os) { + .macos => @intCast(usize, ctx.mcontext.ss.fp), + else => @intCast(usize, ctx.mcontext.regs[29]), + }; dumpStackTraceFromBase(bp, ip); }, else => {}, diff --git a/zig/lib/std/elf.zig b/zig/lib/std/elf.zig index 2d598d0495..a946f247b5 100644 --- a/zig/lib/std/elf.zig +++ b/zig/lib/std/elf.zig @@ -943,7 +943,7 @@ pub const Half = switch (@sizeOf(usize)) { /// Machine architectures /// See current registered ELF machine architectures at: -/// http://www.uxsglobal.com/developers/gabi/latest/ch4.eheader.html +/// http://www.sco.com/developers/gabi/latest/ch4.eheader.html /// The underscore prefix is because many of these start with numbers. pub const EM = enum(u16) { /// No machine diff --git a/zig/lib/std/fmt.zig b/zig/lib/std/fmt.zig index 97dfcc78ba..31171e2028 100644 --- a/zig/lib/std/fmt.zig +++ b/zig/lib/std/fmt.zig @@ -75,111 +75,20 @@ pub fn format( comptime fmt: []const u8, args: anytype, ) !void { - const ArgSetType = u32; - const ArgsType = @TypeOf(args); + const args_type_info = @typeInfo(ArgsType); // XXX: meta.trait.is(.Struct)(ArgsType) doesn't seem to work... - if (@typeInfo(ArgsType) != .Struct) { + if (args_type_info != .Struct) { @compileError("Expected tuple or struct argument, found " ++ @typeName(ArgsType)); } - const fields_info = meta.fields(ArgsType); - if (fields_info.len > @typeInfo(ArgSetType).Int.bits) { + const fields_info = args_type_info.Struct.fields; + if (fields_info.len > max_format_args) { @compileError("32 arguments max are supported per format call"); } - comptime var arg_state: struct { - next_arg: usize = 0, - used_args: usize = 0, - args_len: usize = fields_info.len, - - fn hasUnusedArgs(comptime self: *@This()) bool { - return @popCount(ArgSetType, self.used_args) != self.args_len; - } - - fn nextArg(comptime self: *@This(), comptime arg_index: ?usize) comptime_int { - const next_index = arg_index orelse init: { - const arg = self.next_arg; - self.next_arg += 1; - break :init arg; - }; - - if (next_index >= self.args_len) { - @compileError("Too few arguments"); - } - - // Mark this argument as used - self.used_args |= 1 << next_index; - - return next_index; - } - } = .{}; - - comptime var parser: struct { - buf: []const u8 = undefined, - pos: comptime_int = 0, - - // Returns a decimal number or null if the current character is not a - // digit - fn number(comptime self: *@This()) ?usize { - var r: ?usize = null; - - while (self.pos < self.buf.len) : (self.pos += 1) { - switch (self.buf[self.pos]) { - '0'...'9' => { - if (r == null) r = 0; - r.? *= 10; - r.? += self.buf[self.pos] - '0'; - }, - else => break, - } - } - - return r; - } - - // Returns a substring of the input starting from the current position - // and ending where `ch` is found or until the end if not found - fn until(comptime self: *@This(), comptime ch: u8) []const u8 { - const start = self.pos; - - if (start >= self.buf.len) - return &[_]u8{}; - - while (self.pos < self.buf.len) : (self.pos += 1) { - if (self.buf[self.pos] == ch) break; - } - return self.buf[start..self.pos]; - } - - // Returns one character, if available - fn char(comptime self: *@This()) ?u8 { - if (self.pos < self.buf.len) { - const ch = self.buf[self.pos]; - self.pos += 1; - return ch; - } - return null; - } - - fn maybe(comptime self: *@This(), comptime val: u8) bool { - if (self.pos < self.buf.len and self.buf[self.pos] == val) { - self.pos += 1; - return true; - } - return false; - } - - // Returns the n-th next character or null if that's past the end - fn peek(comptime self: *@This(), comptime n: usize) ?u8 { - return if (self.pos + n < self.buf.len) self.buf[self.pos + n] else null; - } - } = .{}; - - var options: FormatOptions = .{}; - @setEvalBranchQuota(2000000); - + comptime var arg_state: ArgState = .{ .args_len = fields_info.len }; comptime var i = 0; inline while (i < fmt.len) { const start_index = i; @@ -234,134 +143,258 @@ pub fn format( comptime assert(fmt[i] == '}'); i += 1; - options = .{}; - - // Parse the format fragment between braces - parser.buf = fmt[fmt_begin..fmt_end]; - parser.pos = 0; - - // Parse the positional argument number - const opt_pos_arg = comptime init: { - if (parser.maybe('[')) { - const arg_name = parser.until(']'); + const placeholder = comptime parsePlaceholder(fmt[fmt_begin..fmt_end].*); + const arg_pos = comptime switch (placeholder.arg) { + .none => null, + .number => |pos| pos, + .named => |arg_name| meta.fieldIndex(ArgsType, arg_name) orelse + @compileError("No argument with name '" ++ arg_name ++ "'"), + }; - if (!parser.maybe(']')) { - @compileError("Expected closing ]"); - } + const width = switch (placeholder.width) { + .none => null, + .number => |v| v, + .named => |arg_name| blk: { + const arg_i = comptime meta.fieldIndex(ArgsType, arg_name) orelse + @compileError("No argument with name '" ++ arg_name ++ "'"); + _ = comptime arg_state.nextArg(arg_i) orelse @compileError("Too few arguments"); + break :blk @field(args, arg_name); + }, + }; - break :init meta.fieldIndex(ArgsType, arg_name) orelse + const precision = switch (placeholder.precision) { + .none => null, + .number => |v| v, + .named => |arg_name| blk: { + const arg_i = comptime meta.fieldIndex(ArgsType, arg_name) orelse @compileError("No argument with name '" ++ arg_name ++ "'"); - } else { - break :init parser.number(); - } + _ = comptime arg_state.nextArg(arg_i) orelse @compileError("Too few arguments"); + break :blk @field(args, arg_name); + }, }; - // Parse the format specifier - const specifier_arg = comptime parser.until(':'); + const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse + @compileError("Too few arguments"); - // Skip the colon, if present - if (comptime parser.char()) |ch| { - if (ch != ':') { - @compileError("Expected : or }, found '" ++ [1]u8{ch} ++ "'"); - } + try formatType( + @field(args, fields_info[arg_to_print].name), + placeholder.specifier_arg, + FormatOptions{ + .fill = placeholder.fill, + .alignment = placeholder.alignment, + .width = width, + .precision = precision, + }, + writer, + default_max_depth, + ); + } + + if (comptime arg_state.hasUnusedArgs()) { + const missing_count = arg_state.args_len - @popCount(ArgSetType, arg_state.used_args); + switch (missing_count) { + 0 => unreachable, + 1 => @compileError("Unused argument in '" ++ fmt ++ "'"), + else => @compileError((comptime comptimePrint("{d}", .{missing_count})) ++ " unused arguments in '" ++ fmt ++ "'"), } + } +} - // Parse the fill character - // The fill parameter requires the alignment parameter to be specified - // too - if (comptime parser.peek(1)) |ch| { - if (comptime mem.indexOfScalar(u8, "<^>", ch) != null) { - options.fill = comptime parser.char().?; - } +fn parsePlaceholder(comptime str: anytype) Placeholder { + comptime var parser = Parser{ .buf = &str }; + + // Parse the positional argument number + const arg = comptime parser.specifier() catch |err| + @compileError(@errorName(err)); + + // Parse the format specifier + const specifier_arg = comptime parser.until(':'); + + // Skip the colon, if present + if (comptime parser.char()) |ch| { + if (ch != ':') { + @compileError("Expected : or }, found '" ++ [1]u8{ch} ++ "'"); } + } - // Parse the alignment parameter - if (comptime parser.peek(0)) |ch| { - switch (ch) { - '<' => { - options.alignment = .Left; - _ = comptime parser.char(); - }, - '^' => { - options.alignment = .Center; - _ = comptime parser.char(); - }, - '>' => { - options.alignment = .Right; - _ = comptime parser.char(); - }, - else => {}, - } + // Parse the fill character + // The fill parameter requires the alignment parameter to be specified + // too + const fill = comptime if (parser.peek(1)) |ch| + switch (ch) { + '<', '^', '>' => parser.char().?, + else => ' ', + } + else + ' '; + + // Parse the alignment parameter + const alignment: Alignment = comptime if (parser.peek(0)) |ch| init: { + switch (ch) { + '<', '^', '>' => _ = parser.char(), + else => {}, } + break :init switch (ch) { + '<' => .Left, + '^' => .Center, + else => .Right, + }; + } else .Right; - // Parse the width parameter - options.width = comptime init: { - if (parser.maybe('[')) { - const arg_name = parser.until(']'); + // Parse the width parameter + const width = comptime parser.specifier() catch |err| + @compileError(@errorName(err)); - if (!parser.maybe(']')) { - @compileError("Expected closing ]"); - } + // Skip the dot, if present + if (comptime parser.char()) |ch| { + if (ch != '.') { + @compileError("Expected . or }, found '" ++ [1]u8{ch} ++ "'"); + } + } - const index = meta.fieldIndex(ArgsType, arg_name) orelse - @compileError("No argument with name '" ++ arg_name ++ "'"); - const arg_index = arg_state.nextArg(index); + // Parse the precision parameter + const precision = comptime parser.specifier() catch |err| + @compileError(@errorName(err)); - break :init @field(args, fields_info[arg_index].name); - } else { - break :init parser.number(); - } - }; + if (comptime parser.char()) |ch| { + @compileError("Extraneous trailing character '" ++ [1]u8{ch} ++ "'"); + } + + return Placeholder{ + .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*), + .fill = fill, + .alignment = alignment, + .arg = arg, + .width = width, + .precision = precision, + }; +} + +fn cacheString(str: anytype) []const u8 { + return &str; +} + +const Placeholder = struct { + specifier_arg: []const u8, + fill: u8, + alignment: Alignment, + arg: Specifier, + width: Specifier, + precision: Specifier, +}; + +const Specifier = union(enum) { + none, + number: usize, + named: []const u8, +}; - // Skip the dot, if present - if (comptime parser.char()) |ch| { - if (ch != '.') { - @compileError("Expected . or }, found '" ++ [1]u8{ch} ++ "'"); +const Parser = struct { + buf: []const u8, + pos: usize = 0, + + // Returns a decimal number or null if the current character is not a + // digit + fn number(self: *@This()) ?usize { + var r: ?usize = null; + + while (self.pos < self.buf.len) : (self.pos += 1) { + switch (self.buf[self.pos]) { + '0'...'9' => { + if (r == null) r = 0; + r.? *= 10; + r.? += self.buf[self.pos] - '0'; + }, + else => break, } } - // Parse the precision parameter - options.precision = comptime init: { - if (parser.maybe('[')) { - const arg_name = parser.until(']'); + return r; + } - if (!parser.maybe(']')) { - @compileError("Expected closing ]"); - } + // Returns a substring of the input starting from the current position + // and ending where `ch` is found or until the end if not found + fn until(self: *@This(), ch: u8) []const u8 { + const start = self.pos; - const arg_i = meta.fieldIndex(ArgsType, arg_name) orelse - @compileError("No argument with name '" ++ arg_name ++ "'"); - const arg_to_use = arg_state.nextArg(arg_i); + if (start >= self.buf.len) + return &[_]u8{}; - break :init @field(args, fields_info[arg_to_use].name); - } else { - break :init parser.number(); - } - }; + while (self.pos < self.buf.len) : (self.pos += 1) { + if (self.buf[self.pos] == ch) break; + } + return self.buf[start..self.pos]; + } - if (comptime parser.char()) |ch| { - @compileError("Extraneous trailing character '" ++ [1]u8{ch} ++ "'"); + // Returns one character, if available + fn char(self: *@This()) ?u8 { + if (self.pos < self.buf.len) { + const ch = self.buf[self.pos]; + self.pos += 1; + return ch; } + return null; + } - const arg_to_print = comptime arg_state.nextArg(opt_pos_arg); - try formatType( - @field(args, fields_info[arg_to_print].name), - specifier_arg, - options, - writer, - default_max_depth, - ); + fn maybe(self: *@This(), val: u8) bool { + if (self.pos < self.buf.len and self.buf[self.pos] == val) { + self.pos += 1; + return true; + } + return false; } - if (comptime arg_state.hasUnusedArgs()) { - const missing_count = arg_state.args_len - @popCount(ArgSetType, arg_state.used_args); - switch (missing_count) { - 0 => unreachable, - 1 => @compileError("Unused argument in '" ++ fmt ++ "'"), - else => @compileError((comptime comptimePrint("{d}", .{missing_count})) ++ " unused arguments in '" ++ fmt ++ "'"), + // Returns a decimal number or null if the current character is not a + // digit + fn specifier(self: *@This()) !Specifier { + if (self.maybe('[')) { + const arg_name = self.until(']'); + + if (!self.maybe(']')) + return @field(anyerror, "Expected closing ]"); + + return Specifier{ .named = arg_name }; } + if (self.number()) |i| + return Specifier{ .number = i }; + + return Specifier{ .none = {} }; + } + + // Returns the n-th next character or null if that's past the end + fn peek(self: *@This(), n: usize) ?u8 { + return if (self.pos + n < self.buf.len) self.buf[self.pos + n] else null; + } +}; + +const ArgSetType = u32; +const max_format_args = @typeInfo(ArgSetType).Int.bits; + +const ArgState = struct { + next_arg: usize = 0, + used_args: ArgSetType = 0, + args_len: usize, + + fn hasUnusedArgs(self: *@This()) bool { + return @popCount(ArgSetType, self.used_args) != self.args_len; } -} + + fn nextArg(self: *@This(), arg_index: ?usize) ?usize { + const next_index = arg_index orelse init: { + const arg = self.next_arg; + self.next_arg += 1; + break :init arg; + }; + + if (next_index >= self.args_len) { + return null; + } + + // Mark this argument as used + self.used_args |= @as(ArgSetType, 1) << @intCast(u5, next_index); + return next_index; + } +}; pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @TypeOf(writer).Error!void { _ = options; @@ -535,14 +568,19 @@ pub fn formatType( if (actual_fmt.len == 0) @compileError("cannot format array ref without a specifier (i.e. {s} or {*})"); if (info.child == u8) { - if (comptime mem.indexOfScalar(u8, "sxXeE", actual_fmt[0]) != null) { - return formatText(value, actual_fmt, options, writer); + switch (actual_fmt[0]) { + 's', 'x', 'X', 'e', 'E' => { + comptime checkTextFmt(actual_fmt); + return formatBuf(value, options, writer); + }, + else => {}, } } if (comptime std.meta.trait.isZigString(info.child)) { for (value) |item, i| { - if (i != 0) try formatText(", ", actual_fmt, options, writer); - try formatText(item, actual_fmt, options, writer); + comptime checkTextFmt(actual_fmt); + if (i != 0) try formatBuf(", ", options, writer); + try formatBuf(item, options, writer); } return; } @@ -560,8 +598,12 @@ pub fn formatType( return formatType(mem.span(value), actual_fmt, options, writer, max_depth); } if (ptr_info.child == u8) { - if (comptime mem.indexOfScalar(u8, "sxXeE", actual_fmt[0]) != null) { - return formatText(mem.span(value), actual_fmt, options, writer); + switch (actual_fmt[0]) { + 's', 'x', 'X', 'e', 'E' => { + comptime checkTextFmt(actual_fmt); + return formatBuf(mem.span(value), options, writer); + }, + else => {}, } } @compileError("Unknown format string: '" ++ actual_fmt ++ "' for type '" ++ @typeName(T) ++ "'"); @@ -573,8 +615,12 @@ pub fn formatType( return writer.writeAll("{ ... }"); } if (ptr_info.child == u8) { - if (comptime mem.indexOfScalar(u8, "sxXeE", actual_fmt[0]) != null) { - return formatText(value, actual_fmt, options, writer); + switch (actual_fmt[0]) { + 's', 'x', 'X', 'e', 'E' => { + comptime checkTextFmt(actual_fmt); + return formatBuf(value, options, writer); + }, + else => {}, } } try writer.writeAll("{ "); @@ -594,8 +640,12 @@ pub fn formatType( return writer.writeAll("{ ... }"); } if (info.child == u8) { - if (comptime mem.indexOfScalar(u8, "sxXeE", actual_fmt[0]) != null) { - return formatText(&value, actual_fmt, options, writer); + switch (actual_fmt[0]) { + 's', 'x', 'X', 'e', 'E' => { + comptime checkTextFmt(actual_fmt); + return formatBuf(&value, options, writer); + }, + else => {}, } } try writer.writeAll("{ "); @@ -673,7 +723,7 @@ pub fn formatIntValue( if (@typeInfo(@TypeOf(int_value)).Int.bits <= 8) { return formatAsciiChar(@as(u8, int_value), options, writer); } else { - @compileError("Cannot print integer that is larger than 8 bits as a ascii"); + @compileError("Cannot print integer that is larger than 8 bits as an ASCII character"); } } else if (comptime std.mem.eql(u8, fmt, "u")) { if (@typeInfo(@TypeOf(int_value)).Int.bits <= 21) { @@ -881,29 +931,28 @@ pub fn fmtIntSizeBin(value: u64) std.fmt.Formatter(formatSizeBin) { return .{ .data = value }; } +fn checkTextFmt(comptime fmt: []const u8) void { + if (fmt.len != 1) + @compileError("Unsupported format string '" ++ fmt ++ "' when formatting text"); + switch (fmt[0]) { + 'x' => @compileError("specifier 'x' has been deprecated, wrap your argument in std.fmt.fmtSliceHexLower instead"), + 'X' => @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceHexUpper instead"), + 'e' => @compileError("specifier 'e' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeLower instead"), + 'E' => @compileError("specifier 'E' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeUpper instead"), + 'z' => @compileError("specifier 'z' has been deprecated, wrap your argument in std.zig.fmtId instead"), + 'Z' => @compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead"), + else => {}, + } +} + pub fn formatText( bytes: []const u8, comptime fmt: []const u8, options: FormatOptions, writer: anytype, ) !void { - if (comptime std.mem.eql(u8, fmt, "s")) { - return formatBuf(bytes, options, writer); - } else if (comptime (std.mem.eql(u8, fmt, "x"))) { - @compileError("specifier 'x' has been deprecated, wrap your argument in std.fmt.fmtSliceHexLower instead"); - } else if (comptime (std.mem.eql(u8, fmt, "X"))) { - @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceHexUpper instead"); - } else if (comptime (std.mem.eql(u8, fmt, "e"))) { - @compileError("specifier 'e' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeLower instead"); - } else if (comptime (std.mem.eql(u8, fmt, "E"))) { - @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeUpper instead"); - } else if (comptime std.mem.eql(u8, fmt, "z")) { - @compileError("specifier 'z' has been deprecated, wrap your argument in std.zig.fmtId instead"); - } else if (comptime std.mem.eql(u8, fmt, "Z")) { - @compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead"); - } else { - @compileError("Unsupported format string '" ++ fmt ++ "' when formatting text"); - } + comptime checkTextFmt(fmt); + return formatBuf(bytes, options, writer); } pub fn formatAsciiChar( @@ -2210,6 +2259,7 @@ test "float.decimal" { try expectFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)}); try expectFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)}); try expectFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)}); + try expectFmt("f64: 10000000000000.00", "f64: {d:.2}", .{@as(f64, 9999999999999.999)}); } test "float.libc.sanity" { diff --git a/zig/lib/std/fmt/errol.zig b/zig/lib/std/fmt/errol.zig index e697b7d42f..e98c23f6ec 100644 --- a/zig/lib/std/fmt/errol.zig +++ b/zig/lib/std/fmt/errol.zig @@ -92,7 +92,10 @@ pub fn errol3(value: f64, buffer: []u8) FloatDecimal { }; } - return errol3u(value, buffer); + // We generate digits starting at index 1. If rounding a buffer later then it may be + // required to generate a preceding digit in some cases (9.999) in which case we use + // the 0-index for this extra digit. + return errol3u(value, buffer[1..]); } /// Uncorrected Errol3 double to ASCII conversion. @@ -162,11 +165,7 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal { } // digit generation - - // We generate digits starting at index 1. If rounding a buffer later then it may be - // required to generate a preceding digit in some cases (9.999) in which case we use - // the 0-index for this extra digit. - var buf_index: usize = 1; + var buf_index: usize = 0; while (true) { var hdig = @floatToInt(u8, math.floor(high.val)); if ((high.val == @intToFloat(f64, hdig)) and (high.off < 0)) hdig -= 1; @@ -192,7 +191,7 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal { buf_index += 1; return FloatDecimal{ - .digits = buffer[1..buf_index], + .digits = buffer[0..buf_index], .exp = exp, }; } diff --git a/zig/lib/std/fmt/parse_hex_float.zig b/zig/lib/std/fmt/parse_hex_float.zig index 45a289fdd2..83c798ab96 100644 --- a/zig/lib/std/fmt/parse_hex_float.zig +++ b/zig/lib/std/fmt/parse_hex_float.zig @@ -202,18 +202,19 @@ pub fn parseHexFloat(comptime T: type, s: []const u8) !T { exponent += 1; } - // There are two cases to handle: - // - We've truncated more than 0.5ULP (R=S=1), increase the mantissa. - // - We've truncated exactly 0.5ULP (R=1 S=0), increase the mantissa if the - // result is odd (G=1). - // The two checks can be neatly folded as follows. - mantissa |= @boolToInt(mantissa & 0b100 != 0); - mantissa += 1; - + // Whenever the guard bit is one (G=1) and: + // - we've truncated more than 0.5ULP (R=S=1) + // - we've truncated exactly 0.5ULP (R=1 S=0) + // Were are going to increase the mantissa (round up) + const guard_bit_and_half_or_more = (mantissa & 0b110) == 0b110; mantissa >>= 2; exponent += 2; - if (mantissa & (1 << (mantissa_bits + 1)) != 0) { + if (guard_bit_and_half_or_more) { + mantissa += 1; + } + + if (mantissa == (1 << (mantissa_bits + 1))) { // Renormalize, if the exponent overflows we'll catch that below. mantissa >>= 1; exponent += 1; @@ -338,6 +339,7 @@ test "f128" { // // Min denormalized value. .{ .s = "0x1p-16494", .v = math.f128_true_min }, .{ .s = "-0x1p-16494", .v = -math.f128_true_min }, + .{ .s = "0x1.edcb34a235253948765432134674fp-1", .v = 0x1.edcb34a235253948765432134674fp-1 }, }; for (cases) |case| { diff --git a/zig/lib/std/fs.zig b/zig/lib/std/fs.zig index 6e1821178f..0cc0ca8bb6 100644 --- a/zig/lib/std/fs.zig +++ b/zig/lib/std/fs.zig @@ -300,6 +300,7 @@ pub const Dir = struct { buf: [8192]u8, // TODO align(@alignOf(os.system.dirent)), index: usize, end_index: usize, + first_iter: bool, const Self = @This(); @@ -319,6 +320,10 @@ pub const Dir = struct { fn nextDarwin(self: *Self) !?Entry { start_over: while (true) { if (self.index >= self.end_index) { + if (self.first_iter) { + std.os.lseek_SET(self.dir.fd, 0) catch unreachable; // EBADF here likely means that the Dir was not opened with iteration permissions + self.first_iter = false; + } const rc = os.system.__getdirentries64( self.dir.fd, &self.buf, @@ -369,6 +374,10 @@ pub const Dir = struct { fn nextSolaris(self: *Self) !?Entry { start_over: while (true) { if (self.index >= self.end_index) { + if (self.first_iter) { + std.os.lseek_SET(self.dir.fd, 0) catch unreachable; // EBADF here likely means that the Dir was not opened with iteration permissions + self.first_iter = false; + } const rc = os.system.getdents(self.dir.fd, &self.buf, self.buf.len); switch (os.errno(rc)) { .SUCCESS => {}, @@ -423,6 +432,10 @@ pub const Dir = struct { fn nextBsd(self: *Self) !?Entry { start_over: while (true) { if (self.index >= self.end_index) { + if (self.first_iter) { + std.os.lseek_SET(self.dir.fd, 0) catch unreachable; // EBADF here likely means that the Dir was not opened with iteration permissions + self.first_iter = false; + } const rc = if (builtin.os.tag == .netbsd) os.system.__getdents30(self.dir.fd, &self.buf, self.buf.len) else @@ -479,6 +492,7 @@ pub const Dir = struct { buf: [8192]u8, // TODO align(@alignOf(os.dirent64)), index: usize, end_index: usize, + first_iter: bool, const Self = @This(); @@ -491,6 +505,10 @@ pub const Dir = struct { // TODO: find a better max const HAIKU_MAX_COUNT = 10000; if (self.index >= self.end_index) { + if (self.first_iter) { + std.os.lseek_SET(self.dir.fd, 0) catch unreachable; // EBADF here likely means that the Dir was not opened with iteration permissions + self.first_iter = false; + } const rc = os.system._kern_read_dir( self.dir.fd, &self.buf, @@ -563,6 +581,7 @@ pub const Dir = struct { buf: [8192]u8 align(if (builtin.os.tag != .linux) 1 else @alignOf(linux.dirent64)), index: usize, end_index: usize, + first_iter: bool, const Self = @This(); const linux = os.linux; @@ -574,6 +593,10 @@ pub const Dir = struct { pub fn next(self: *Self) Error!?Entry { start_over: while (true) { if (self.index >= self.end_index) { + if (self.first_iter) { + std.os.lseek_SET(self.dir.fd, 0) catch unreachable; // EBADF here likely means that the Dir was not opened with iteration permissions + self.first_iter = false; + } const rc = linux.getdents64(self.dir.fd, &self.buf, self.buf.len); switch (linux.getErrno(rc)) { .SUCCESS => {}, @@ -620,7 +643,7 @@ pub const Dir = struct { buf: [8192]u8 align(@alignOf(os.windows.FILE_BOTH_DIR_INFORMATION)), index: usize, end_index: usize, - first: bool, + first_iter: bool, name_data: [256]u8, const Self = @This(); @@ -645,9 +668,9 @@ pub const Dir = struct { .FileBothDirectoryInformation, w.FALSE, null, - if (self.first) @as(w.BOOLEAN, w.TRUE) else @as(w.BOOLEAN, w.FALSE), + if (self.first_iter) @as(w.BOOLEAN, w.TRUE) else @as(w.BOOLEAN, w.FALSE), ); - self.first = false; + self.first_iter = false; if (io.Information == 0) return null; self.index = 0; self.end_index = io.Information; @@ -769,18 +792,20 @@ pub const Dir = struct { .index = 0, .end_index = 0, .buf = undefined, + .first_iter = true, }, .linux, .haiku => return Iterator{ .dir = self, .index = 0, .end_index = 0, .buf = undefined, + .first_iter = true, }, .windows => return Iterator{ .dir = self, .index = 0, .end_index = 0, - .first = true, + .first_iter = true, .buf = undefined, .name_data = undefined, }, diff --git a/zig/lib/std/fs/get_app_data_dir.zig b/zig/lib/std/fs/get_app_data_dir.zig index a60e9e5c59..4f7ba9af62 100644 --- a/zig/lib/std/fs/get_app_data_dir.zig +++ b/zig/lib/std/fs/get_app_data_dir.zig @@ -45,6 +45,10 @@ pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDi return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname }); }, .linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris => { + if (os.getenv("XDG_DATA_HOME")) |xdg| { + return fs.path.join(allocator, &[_][]const u8{ xdg, appname }); + } + const home_dir = os.getenv("HOME") orelse { // TODO look in /etc/passwd return error.AppDataDirUnavailable; diff --git a/zig/lib/std/fs/path.zig b/zig/lib/std/fs/path.zig index 323f974255..fbf5bd99ee 100644 --- a/zig/lib/std/fs/path.zig +++ b/zig/lib/std/fs/path.zig @@ -14,11 +14,17 @@ const native_os = builtin.target.os.tag; pub const sep_windows = '\\'; pub const sep_posix = '/'; -pub const sep = if (native_os == .windows) sep_windows else sep_posix; +pub const sep = switch (native_os) { + .windows, .uefi => sep_windows, + else => sep_posix, +}; pub const sep_str_windows = "\\"; pub const sep_str_posix = "/"; -pub const sep_str = if (native_os == .windows) sep_str_windows else sep_str_posix; +pub const sep_str = switch (native_os) { + .windows, .uefi => sep_str_windows, + else => sep_str_posix, +}; pub const delimiter_windows = ';'; pub const delimiter_posix = ':'; @@ -26,11 +32,11 @@ pub const delimiter = if (native_os == .windows) delimiter_windows else delimite /// Returns if the given byte is a valid path separator pub fn isSep(byte: u8) bool { - if (native_os == .windows) { - return byte == '/' or byte == '\\'; - } else { - return byte == '/'; - } + return switch (native_os) { + .windows => byte == '/' or byte == '\\', + .uefi => byte == '\\', + else => byte == '/', + }; } /// This is different from mem.join in that the separator will not be repeated if @@ -110,6 +116,17 @@ pub fn joinZ(allocator: Allocator, paths: []const []const u8) ![:0]u8 { return out[0 .. out.len - 1 :0]; } +fn testJoinMaybeZUefi(paths: []const []const u8, expected: []const u8, zero: bool) !void { + const uefiIsSep = struct { + fn isSep(byte: u8) bool { + return byte == '\\'; + } + }.isSep; + const actual = try joinSepMaybeZ(testing.allocator, sep_windows, uefiIsSep, paths, zero); + defer testing.allocator.free(actual); + try testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual); +} + fn testJoinMaybeZWindows(paths: []const []const u8, expected: []const u8, zero: bool) !void { const windowsIsSep = struct { fn isSep(byte: u8) bool { @@ -158,6 +175,11 @@ test "join" { zero, ); + try testJoinMaybeZUefi(&[_][]const u8{ "EFI", "Boot", "bootx64.efi" }, "EFI\\Boot\\bootx64.efi", zero); + try testJoinMaybeZUefi(&[_][]const u8{ "EFI\\Boot", "bootx64.efi" }, "EFI\\Boot\\bootx64.efi", zero); + try testJoinMaybeZUefi(&[_][]const u8{ "EFI\\", "\\Boot", "bootx64.efi" }, "EFI\\Boot\\bootx64.efi", zero); + try testJoinMaybeZUefi(&[_][]const u8{ "EFI\\", "\\Boot\\", "\\bootx64.efi" }, "EFI\\Boot\\bootx64.efi", zero); + try testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero); try testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero); diff --git a/zig/lib/std/fs/test.zig b/zig/lib/std/fs/test.zig index 1ab6608327..2e4d457179 100644 --- a/zig/lib/std/fs/test.zig +++ b/zig/lib/std/fs/test.zig @@ -180,6 +180,39 @@ test "Dir.Iterator" { try testing.expect(contains(&entries, Dir.Entry{ .name = "some_dir", .kind = Dir.Entry.Kind.Directory })); } +test "Dir.Iterator twice" { + var tmp_dir = tmpDir(.{ .iterate = true }); + defer tmp_dir.cleanup(); + + // First, create a couple of entries to iterate over. + const file = try tmp_dir.dir.createFile("some_file", .{}); + file.close(); + + try tmp_dir.dir.makeDir("some_dir"); + + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + + var i: u8 = 0; + while (i < 2) : (i += 1) { + var entries = std.ArrayList(Dir.Entry).init(allocator); + + // Create iterator. + var iter = tmp_dir.dir.iterate(); + while (try iter.next()) |entry| { + // We cannot just store `entry` as on Windows, we're re-using the name buffer + // which means we'll actually share the `name` pointer between entries! + const name = try allocator.dupe(u8, entry.name); + try entries.append(Dir.Entry{ .name = name, .kind = entry.kind }); + } + + try testing.expect(entries.items.len == 2); // note that the Iterator skips '.' and '..' + try testing.expect(contains(&entries, Dir.Entry{ .name = "some_file", .kind = Dir.Entry.Kind.File })); + try testing.expect(contains(&entries, Dir.Entry{ .name = "some_dir", .kind = Dir.Entry.Kind.Directory })); + } +} + fn entryEql(lhs: Dir.Entry, rhs: Dir.Entry) bool { return mem.eql(u8, lhs.name, rhs.name) and lhs.kind == rhs.kind; } diff --git a/zig/lib/std/hash_map.zig b/zig/lib/std/hash_map.zig index 851df83f84..15b62e0d40 100644 --- a/zig/lib/std/hash_map.zig +++ b/zig/lib/std/hash_map.zig @@ -750,12 +750,19 @@ pub fn HashMapUnmanaged( fingerprint: FingerPrint = free, used: u1 = 0, + const slot_free = @bitCast(u8, Metadata{ .fingerprint = free }); + const slot_tombstone = @bitCast(u8, Metadata{ .fingerprint = tombstone }); + pub fn isUsed(self: Metadata) bool { return self.used == 1; } pub fn isTombstone(self: Metadata) bool { - return !self.isUsed() and self.fingerprint == tombstone; + return @bitCast(u8, self) == slot_tombstone; + } + + pub fn isFree(self: Metadata) bool { + return @bitCast(u8, self) == slot_free; } pub fn takeFingerprint(hash: Hash) FingerPrint { @@ -1115,7 +1122,7 @@ pub fn HashMapUnmanaged( var idx = @truncate(usize, hash & mask); var metadata = self.metadata.? + idx; - while ((metadata[0].isUsed() or metadata[0].isTombstone()) and limit != 0) { + while (!metadata[0].isFree() and limit != 0) { if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { const test_key = &self.keys()[idx]; // If you get a compile error on this line, it means that your generic eql @@ -1294,7 +1301,7 @@ pub fn HashMapUnmanaged( var first_tombstone_idx: usize = self.capacity(); // invalid index var metadata = self.metadata.? + idx; - while ((metadata[0].isUsed() or metadata[0].isTombstone()) and limit != 0) { + while (!metadata[0].isFree() and limit != 0) { if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { const test_key = &self.keys()[idx]; // If you get a compile error on this line, it means that your generic eql diff --git a/zig/lib/std/io/reader.zig b/zig/lib/std/io/reader.zig index 2839552668..b356ec0629 100644 --- a/zig/lib/std/io/reader.zig +++ b/zig/lib/std/io/reader.zig @@ -107,16 +107,16 @@ pub fn Reader( ) !void { array_list.shrinkRetainingCapacity(0); while (true) { + if (array_list.items.len == max_size) { + return error.StreamTooLong; + } + var byte: u8 = try self.readByte(); if (byte == delimiter) { return; } - if (array_list.items.len == max_size) { - return error.StreamTooLong; - } - try array_list.append(byte); } } @@ -139,17 +139,20 @@ pub fn Reader( /// Reads from the stream until specified byte is found. If the buffer is not /// large enough to hold the entire contents, `error.StreamTooLong` is returned. + /// If end-of-stream is found, `error.EndOfStream` is returned. /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The - /// delimiter byte is not included in the returned slice. + /// delimiter byte is written to the output buffer but is not included + /// in the returned slice. pub fn readUntilDelimiter(self: Self, buf: []u8, delimiter: u8) ![]u8 { var index: usize = 0; while (true) { + if (index >= buf.len) return error.StreamTooLong; + const byte = try self.readByte(); + buf[index] = byte; if (byte == delimiter) return buf[0..index]; - if (index >= buf.len) return error.StreamTooLong; - buf[index] = byte; index += 1; } } @@ -185,10 +188,13 @@ pub fn Reader( /// If end-of-stream is found, returns the rest of the stream. If this /// function is called again after that, returns null. /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The - /// delimiter byte is not included in the returned slice. + /// delimiter byte is written to the output buffer but is not included + /// in the returned slice. pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) !?[]u8 { var index: usize = 0; while (true) { + if (index >= buf.len) return error.StreamTooLong; + const byte = self.readByte() catch |err| switch (err) { error.EndOfStream => { if (index == 0) { @@ -199,11 +205,10 @@ pub fn Reader( }, else => |e| return e, }; + buf[index] = byte; if (byte == delimiter) return buf[0..index]; - if (index >= buf.len) return error.StreamTooLong; - buf[index] = byte; index += 1; } } @@ -363,3 +368,272 @@ test "Reader.skipBytes" { try reader.skipBytes(0, .{}); try testing.expectError(error.EndOfStream, reader.skipBytes(1, .{})); } + +test "Reader.readUntilDelimiterArrayList returns ArrayLists with bytes read until the delimiter, then EndOfStream" { + const a = std.testing.allocator; + var list = std.ArrayList(u8).init(a); + defer list.deinit(); + + const reader = std.io.fixedBufferStream("0000\n1234\n").reader(); + + try reader.readUntilDelimiterArrayList(&list, '\n', 5); + try std.testing.expectEqualStrings("0000", list.items); + try reader.readUntilDelimiterArrayList(&list, '\n', 5); + try std.testing.expectEqualStrings("1234", list.items); + try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterArrayList(&list, '\n', 5)); +} + +test "Reader.readUntilDelimiterArrayList returns an empty ArrayList" { + const a = std.testing.allocator; + var list = std.ArrayList(u8).init(a); + defer list.deinit(); + + const reader = std.io.fixedBufferStream("\n").reader(); + + try reader.readUntilDelimiterArrayList(&list, '\n', 5); + try std.testing.expectEqualStrings("", list.items); +} + +test "Reader.readUntilDelimiterArrayList returns StreamTooLong, then an ArrayList with bytes read until the delimiter" { + const a = std.testing.allocator; + var list = std.ArrayList(u8).init(a); + defer list.deinit(); + + const reader = std.io.fixedBufferStream("1234567\n").reader(); + + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterArrayList(&list, '\n', 5)); + try std.testing.expectEqualStrings("12345", list.items); + try reader.readUntilDelimiterArrayList(&list, '\n', 5); + try std.testing.expectEqualStrings("67", list.items); +} + +test "Reader.readUntilDelimiterArrayList returns EndOfStream" { + const a = std.testing.allocator; + var list = std.ArrayList(u8).init(a); + defer list.deinit(); + + const reader = std.io.fixedBufferStream("1234").reader(); + + try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterArrayList(&list, '\n', 5)); + try std.testing.expectEqualStrings("1234", list.items); +} + +test "Reader.readUntilDelimiterAlloc returns ArrayLists with bytes read until the delimiter, then EndOfStream" { + const a = std.testing.allocator; + + const reader = std.io.fixedBufferStream("0000\n1234\n").reader(); + + { + var result = try reader.readUntilDelimiterAlloc(a, '\n', 5); + defer a.free(result); + try std.testing.expectEqualStrings("0000", result); + } + + { + var result = try reader.readUntilDelimiterAlloc(a, '\n', 5); + defer a.free(result); + try std.testing.expectEqualStrings("1234", result); + } + + try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterAlloc(a, '\n', 5)); +} + +test "Reader.readUntilDelimiterAlloc returns an empty ArrayList" { + const a = std.testing.allocator; + + const reader = std.io.fixedBufferStream("\n").reader(); + + { + var result = try reader.readUntilDelimiterAlloc(a, '\n', 5); + defer a.free(result); + try std.testing.expectEqualStrings("", result); + } +} + +test "Reader.readUntilDelimiterAlloc returns StreamTooLong, then an ArrayList with bytes read until the delimiter" { + const a = std.testing.allocator; + + const reader = std.io.fixedBufferStream("1234567\n").reader(); + + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterAlloc(a, '\n', 5)); + + var result = try reader.readUntilDelimiterAlloc(a, '\n', 5); + defer a.free(result); + try std.testing.expectEqualStrings("67", result); +} + +test "Reader.readUntilDelimiterAlloc returns EndOfStream" { + const a = std.testing.allocator; + + const reader = std.io.fixedBufferStream("1234").reader(); + + try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterAlloc(a, '\n', 5)); +} + +test "Reader.readUntilDelimiter returns bytes read until the delimiter" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("0000\n1234\n").reader(); + try std.testing.expectEqualStrings("0000", try reader.readUntilDelimiter(&buf, '\n')); + try std.testing.expectEqualStrings("1234", try reader.readUntilDelimiter(&buf, '\n')); +} + +test "Reader.readUntilDelimiter returns an empty string" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("\n").reader(); + try std.testing.expectEqualStrings("", try reader.readUntilDelimiter(&buf, '\n')); +} + +test "Reader.readUntilDelimiter returns StreamTooLong, then an empty string" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("12345\n").reader(); + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n')); + try std.testing.expectEqualStrings("", try reader.readUntilDelimiter(&buf, '\n')); +} + +test "Reader.readUntilDelimiter returns StreamTooLong, then bytes read until the delimiter" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("1234567\n").reader(); + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n')); + try std.testing.expectEqualStrings("67", try reader.readUntilDelimiter(&buf, '\n')); +} + +test "Reader.readUntilDelimiter returns EndOfStream" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("").reader(); + try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n')); +} + +test "Reader.readUntilDelimiter returns bytes read until delimiter, then EndOfStream" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("1234\n").reader(); + try std.testing.expectEqualStrings("1234", try reader.readUntilDelimiter(&buf, '\n')); + try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n')); +} + +test "Reader.readUntilDelimiter returns EndOfStream" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("1234").reader(); + try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n')); +} + +test "Reader.readUntilDelimiter returns StreamTooLong, then EndOfStream" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("12345").reader(); + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n')); + try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n')); +} + +test "Reader.readUntilDelimiter writes all bytes read to the output buffer" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("0000\n12345").reader(); + _ = try reader.readUntilDelimiter(&buf, '\n'); + try std.testing.expectEqualStrings("0000\n", &buf); + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n')); + try std.testing.expectEqualStrings("12345", &buf); +} + +test "Reader.readUntilDelimiterOrEofAlloc returns ArrayLists with bytes read until the delimiter, then EndOfStream" { + const a = std.testing.allocator; + + const reader = std.io.fixedBufferStream("0000\n1234\n").reader(); + + { + var result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?; + defer a.free(result); + try std.testing.expectEqualStrings("0000", result); + } + + { + var result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?; + defer a.free(result); + try std.testing.expectEqualStrings("1234", result); + } + + try std.testing.expect((try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)) == null); +} + +test "Reader.readUntilDelimiterOrEofAlloc returns an empty ArrayList" { + const a = std.testing.allocator; + + const reader = std.io.fixedBufferStream("\n").reader(); + + { + var result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?; + defer a.free(result); + try std.testing.expectEqualStrings("", result); + } +} + +test "Reader.readUntilDelimiterOrEofAlloc returns StreamTooLong, then an ArrayList with bytes read until the delimiter" { + const a = std.testing.allocator; + + const reader = std.io.fixedBufferStream("1234567\n").reader(); + + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)); + + var result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?; + defer a.free(result); + try std.testing.expectEqualStrings("67", result); +} + +test "Reader.readUntilDelimiterOrEof returns bytes read until the delimiter" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("0000\n1234\n").reader(); + try std.testing.expectEqualStrings("0000", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?); + try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?); +} + +test "Reader.readUntilDelimiterOrEof returns an empty string" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("\n").reader(); + try std.testing.expectEqualStrings("", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?); +} + +test "Reader.readUntilDelimiterOrEof returns StreamTooLong, then an empty string" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("12345\n").reader(); + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n')); + try std.testing.expectEqualStrings("", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?); +} + +test "Reader.readUntilDelimiterOrEof returns StreamTooLong, then bytes read until the delimiter" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("1234567\n").reader(); + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n')); + try std.testing.expectEqualStrings("67", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?); +} + +test "Reader.readUntilDelimiterOrEof returns null" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("").reader(); + try std.testing.expect((try reader.readUntilDelimiterOrEof(&buf, '\n')) == null); +} + +test "Reader.readUntilDelimiterOrEof returns bytes read until delimiter, then null" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("1234\n").reader(); + try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?); + try std.testing.expect((try reader.readUntilDelimiterOrEof(&buf, '\n')) == null); +} + +test "Reader.readUntilDelimiterOrEof returns bytes read until end-of-stream" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("1234").reader(); + try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?); +} + +test "Reader.readUntilDelimiterOrEof returns StreamTooLong, then bytes read until end-of-stream" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("1234567").reader(); + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n')); + try std.testing.expectEqualStrings("67", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?); +} + +test "Reader.readUntilDelimiterOrEof writes all bytes read to the output buffer" { + var buf: [5]u8 = undefined; + const reader = std.io.fixedBufferStream("0000\n12345").reader(); + _ = try reader.readUntilDelimiterOrEof(&buf, '\n'); + try std.testing.expectEqualStrings("0000\n", &buf); + try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n')); + try std.testing.expectEqualStrings("12345", &buf); +} diff --git a/zig/lib/std/math/isnormal.zig b/zig/lib/std/math/isnormal.zig index 0430e1367a..88e186a3c9 100644 --- a/zig/lib/std/math/isnormal.zig +++ b/zig/lib/std/math/isnormal.zig @@ -9,19 +9,19 @@ pub fn isNormal(x: anytype) bool { switch (T) { f16 => { const bits = @bitCast(u16, x); - return (bits + (1 << 10)) & (maxInt(u16) >> 1) >= (1 << 11); + return (bits +% (1 << 10)) & (maxInt(u16) >> 1) >= (1 << 11); }, f32 => { const bits = @bitCast(u32, x); - return (bits + (1 << 23)) & (maxInt(u32) >> 1) >= (1 << 24); + return (bits +% (1 << 23)) & (maxInt(u32) >> 1) >= (1 << 24); }, f64 => { const bits = @bitCast(u64, x); - return (bits + (1 << 52)) & (maxInt(u64) >> 1) >= (1 << 53); + return (bits +% (1 << 52)) & (maxInt(u64) >> 1) >= (1 << 53); }, f128 => { const bits = @bitCast(u128, x); - return (bits + (1 << 112)) & (maxInt(u128) >> 1) >= (1 << 113); + return (bits +% (1 << 112)) & (maxInt(u128) >> 1) >= (1 << 113); }, else => { @compileError("isNormal not implemented for " ++ @typeName(T)); @@ -34,6 +34,18 @@ test "math.isNormal" { try expect(!isNormal(math.nan(f32))); try expect(!isNormal(math.nan(f64))); try expect(!isNormal(math.nan(f128))); + try expect(!isNormal(-math.nan(f16))); + try expect(!isNormal(-math.nan(f32))); + try expect(!isNormal(-math.nan(f64))); + try expect(!isNormal(-math.nan(f128))); + try expect(!isNormal(math.inf(f16))); + try expect(!isNormal(math.inf(f32))); + try expect(!isNormal(math.inf(f64))); + try expect(!isNormal(math.inf(f128))); + try expect(!isNormal(-math.inf(f16))); + try expect(!isNormal(-math.inf(f32))); + try expect(!isNormal(-math.inf(f64))); + try expect(!isNormal(-math.inf(f128))); try expect(!isNormal(@as(f16, 0))); try expect(!isNormal(@as(f32, 0))); try expect(!isNormal(@as(f64, 0))); diff --git a/zig/lib/std/mem.zig b/zig/lib/std/mem.zig index dc6b4bcd4c..dd78de3cc8 100644 --- a/zig/lib/std/mem.zig +++ b/zig/lib/std/mem.zig @@ -275,7 +275,9 @@ pub fn zeroes(comptime T: type) T { } else { var structure: T = undefined; inline for (struct_info.fields) |field| { - @field(structure, field.name) = zeroes(@TypeOf(@field(structure, field.name))); + if (!field.is_comptime) { + @field(structure, field.name) = zeroes(@TypeOf(@field(structure, field.name))); + } } return structure; } @@ -306,9 +308,7 @@ pub fn zeroes(comptime T: type) T { if (comptime meta.containerLayout(T) == .Extern) { // The C language specification states that (global) unions // should be zero initialized to the first named member. - var item: T = undefined; - @field(item, info.fields[0].name) = zeroes(@TypeOf(@field(item, info.fields[0].name))); - return item; + return @unionInit(T, info.fields[0].name, zeroes(info.fields[0].field_type)); } @compileError("Can't set a " ++ @typeName(T) ++ " to zero."); @@ -342,6 +342,8 @@ test "mem.zeroes" { try testing.expect(a.y == 10); const ZigStruct = struct { + comptime comptime_field: u8 = 5, + integral_types: struct { integer_0: i0, integer_8: i8, @@ -376,6 +378,7 @@ test "mem.zeroes" { }; const b = zeroes(ZigStruct); + try testing.expectEqual(@as(u8, 5), b.comptime_field); try testing.expectEqual(@as(i8, 0), b.integral_types.integer_0); try testing.expectEqual(@as(i8, 0), b.integral_types.integer_8); try testing.expectEqual(@as(i16, 0), b.integral_types.integer_16); @@ -411,6 +414,9 @@ test "mem.zeroes" { var c = zeroes(C_union); try testing.expectEqual(@as(u8, 0), c.a); + + comptime var comptime_union = zeroes(C_union); + try testing.expectEqual(@as(u8, 0), comptime_union.a); } /// Initializes all fields of the struct with their default value, or zero values if no default value is present. @@ -715,7 +721,7 @@ fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type { @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T)); } -/// Takes a pointer to an array, an array, a sentinel-terminated pointer, or a slice and +/// Takes an array, a pointer to an array, a sentinel-terminated pointer, or a slice and /// iterates searching for the first occurrence of `end`, returning the scanned slice. /// If `end` is not found, the full length of the array/slice/sentinel terminated pointer is returned. /// If the pointer type is sentinel terminated and `end` matches that terminator, the diff --git a/zig/lib/std/multi_array_list.zig b/zig/lib/std/multi_array_list.zig index a651076aba..47d12884df 100644 --- a/zig/lib/std/multi_array_list.zig +++ b/zig/lib/std/multi_array_list.zig @@ -188,7 +188,7 @@ pub fn MultiArrayList(comptime S: type) type { /// after and including the specified index back by one and /// sets the given index to the specified element. May reallocate /// and invalidate iterators. - pub fn insert(self: *Self, gpa: Allocator, index: usize, elem: S) void { + pub fn insert(self: *Self, gpa: Allocator, index: usize, elem: S) !void { try self.ensureUnusedCapacity(gpa, 1); self.insertAssumeCapacity(index, elem); } @@ -602,3 +602,22 @@ test "ensure capacity on empty list" { try testing.expectEqualSlices(u32, &[_]u32{ 9, 11 }, list.items(.a)); try testing.expectEqualSlices(u8, &[_]u8{ 10, 12 }, list.items(.b)); } + +test "insert elements" { + const ally = testing.allocator; + + const Foo = struct { + a: u8, + b: u32, + }; + + var list = MultiArrayList(Foo){}; + defer list.deinit(ally); + + try list.insert(ally, 0, .{ .a = 1, .b = 2 }); + try list.ensureUnusedCapacity(ally, 1); + list.insertAssumeCapacity(1, .{ .a = 2, .b = 3 }); + + try testing.expectEqualSlices(u8, &[_]u8{ 1, 2 }, list.items(.a)); + try testing.expectEqualSlices(u32, &[_]u32{ 2, 3 }, list.items(.b)); +} diff --git a/zig/lib/std/net.zig b/zig/lib/std/net.zig index 1165ac6073..f564a9dbd5 100644 --- a/zig/lib/std/net.zig +++ b/zig/lib/std/net.zig @@ -636,17 +636,35 @@ pub fn connectUnixSocket(path: []const u8) !Stream { } fn if_nametoindex(name: []const u8) !u32 { - var ifr: os.ifreq = undefined; - var sockfd = try os.socket(os.AF.UNIX, os.SOCK.DGRAM | os.SOCK.CLOEXEC, 0); - defer os.closeSocket(sockfd); + if (builtin.target.os.tag == .linux) { + var ifr: os.ifreq = undefined; + var sockfd = try os.socket(os.AF.UNIX, os.SOCK.DGRAM | os.SOCK.CLOEXEC, 0); + defer os.closeSocket(sockfd); + + std.mem.copy(u8, &ifr.ifrn.name, name); + ifr.ifrn.name[name.len] = 0; + + // TODO investigate if this needs to be integrated with evented I/O. + try os.ioctl_SIOCGIFINDEX(sockfd, &ifr); - std.mem.copy(u8, &ifr.ifrn.name, name); - ifr.ifrn.name[name.len] = 0; + return @bitCast(u32, ifr.ifru.ivalue); + } + + if (comptime builtin.target.os.tag.isDarwin()) { + if (name.len >= os.IFNAMESIZE) + return error.NameTooLong; - // TODO investigate if this needs to be integrated with evented I/O. - try os.ioctl_SIOCGIFINDEX(sockfd, &ifr); + var if_name: [os.IFNAMESIZE:0]u8 = undefined; + std.mem.copy(u8, &if_name, name); + if_name[name.len] = 0; + const if_slice = if_name[0..name.len :0]; + const index = os.system.if_nametoindex(if_slice); + if (index == 0) + return error.InterfaceNotFound; + return @bitCast(u32, index); + } - return @bitCast(u32, ifr.ifru.ivalue); + @compileError("std.net.if_nametoindex unimplemented for this OS"); } pub const AddressList = struct { diff --git a/zig/lib/std/net/test.zig b/zig/lib/std/net/test.zig index f181bb49ea..f2946777bd 100644 --- a/zig/lib/std/net/test.zig +++ b/zig/lib/std/net/test.zig @@ -49,7 +49,7 @@ test "parse and render IPv6 addresses" { try testing.expectError(error.Incomplete, net.Address.parseIp6("FF01:", 0)); try testing.expectError(error.InvalidIpv4Mapping, net.Address.parseIp6("::123.123.123.123", 0)); // TODO Make this test pass on other operating systems. - if (builtin.os.tag == .linux) { + if (builtin.os.tag == .linux or comptime builtin.os.tag.isDarwin()) { try testing.expectError(error.Incomplete, net.Address.resolveIp6("ff01::fb%", 0)); try testing.expectError(error.Overflow, net.Address.resolveIp6("ff01::fb%wlp3s0s0s0s0s0s0s0s0", 0)); try testing.expectError(error.Overflow, net.Address.resolveIp6("ff01::fb%12345678901234", 0)); @@ -57,7 +57,7 @@ test "parse and render IPv6 addresses" { } test "invalid but parseable IPv6 scope ids" { - if (builtin.os.tag != .linux) { + if (builtin.os.tag != .linux or comptime !builtin.os.tag.isDarwin()) { // Currently, resolveIp6 with alphanumerical scope IDs only works on Linux. // TODO Make this test pass on other operating systems. return error.SkipZigTest; diff --git a/zig/lib/std/os.zig b/zig/lib/std/os.zig index e16a660741..76843b4b6f 100644 --- a/zig/lib/std/os.zig +++ b/zig/lib/std/os.zig @@ -163,6 +163,7 @@ pub const sigset_t = system.sigset_t; pub const sockaddr = system.sockaddr; pub const socklen_t = system.socklen_t; pub const stack_t = system.stack_t; +pub const tcflag_t = system.tcflag_t; pub const termios = system.termios; pub const time_t = system.time_t; pub const timespec = system.timespec; @@ -992,7 +993,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { /// transfer further bytes or may result in an error (e.g., if the disk is now full). /// /// For POSIX systems, if `fd` is opened in non blocking mode, the function will -/// return error.WouldBlock when EAGAIN is received.k`. +/// return error.WouldBlock when EAGAIN is received. /// On Windows, if the application has a global event loop enabled, I/O Completion Ports are /// used to perform the I/O. `error.WouldBlock` is not possible on Windows. /// diff --git a/zig/lib/std/os/linux.zig b/zig/lib/std/os/linux.zig index 9548f9afb0..cc9a8bc85c 100644 --- a/zig/lib/std/os/linux.zig +++ b/zig/lib/std/os/linux.zig @@ -440,26 +440,30 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize { } pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: i64) usize { - const offset_halves = splitValueLE64(offset); + const offset_u = @bitCast(u64, offset); return syscall5( .preadv, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count, - offset_halves[0], - offset_halves[1], + // Kernel expects the offset is splitted into largest natural word-size. + // See following link for detail: + // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=601cc11d054ae4b5e9b5babec3d8e4667a2cb9b5 + @truncate(usize, offset_u), + if (usize_bits < 64) @truncate(usize, offset_u >> 32) else 0, ); } pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: i64, flags: kernel_rwf) usize { - const offset_halves = splitValue64(offset); + const offset_u = @bitCast(u64, offset); return syscall6( .preadv2, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count, - offset_halves[0], - offset_halves[1], + // See comments in preadv + @truncate(usize, offset_u), + if (usize_bits < 64) @truncate(usize, offset_u >> 32) else 0, flags, ); } @@ -473,26 +477,28 @@ pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize { } pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: i64) usize { - const offset_halves = splitValueLE64(offset); + const offset_u = @bitCast(u64, offset); return syscall5( .pwritev, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count, - offset_halves[0], - offset_halves[1], + // See comments in preadv + @truncate(usize, offset_u), + if (usize_bits < 64) @truncate(usize, offset_u >> 32) else 0, ); } pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: i64, flags: kernel_rwf) usize { - const offset_halves = splitValue64(offset); + const offset_u = @bitCast(u64, offset); return syscall6( .pwritev2, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count, - offset_halves[0], - offset_halves[1], + // See comments in preadv + @truncate(usize, offset_u), + if (usize_bits < 64) @truncate(usize, offset_u >> 32) else 0, flags, ); } @@ -738,7 +744,11 @@ pub fn fchmod(fd: i32, mode: mode_t) usize { } pub fn fchown(fd: i32, owner: uid_t, group: gid_t) usize { - return syscall3(.fchown, @bitCast(usize, @as(isize, fd)), owner, group); + if (@hasField(SYS, "fchown32")) { + return syscall3(.fchown32, @bitCast(usize, @as(isize, fd)), owner, group); + } else { + return syscall3(.fchown, @bitCast(usize, @as(isize, fd)), owner, group); + } } /// Can only be called on 32 bit systems. For 64 bit see `lseek`. diff --git a/zig/lib/std/os/linux/io_uring.zig b/zig/lib/std/os/linux/io_uring.zig index d2d9e64bda..fc32508cf5 100644 --- a/zig/lib/std/os/linux/io_uring.zig +++ b/zig/lib/std/os/linux/io_uring.zig @@ -300,9 +300,10 @@ pub const IO_Uring = struct { /// A convenience method for `copy_cqes()` for when you don't need to batch or peek. pub fn copy_cqe(ring: *IO_Uring) !io_uring_cqe { var cqes: [1]io_uring_cqe = undefined; - const count = try ring.copy_cqes(&cqes, 1); - assert(count == 1); - return cqes[0]; + while (true) { + const count = try ring.copy_cqes(&cqes, 1); + if (count > 0) return cqes[0]; + } } /// Matches the implementation of cq_ring_needs_flush() in liburing. @@ -2471,7 +2472,7 @@ test "renameat" { switch (cqe.err()) { .SUCCESS => {}, // This kernel's io_uring does not yet implement renameat (kernel version < 5.11) - .INVAL => return error.SkipZigTest, + .BADF, .INVAL => return error.SkipZigTest, else => |errno| std.debug.panic("unhandled errno: {}", .{errno}), } try testing.expectEqual(linux.io_uring_cqe{ @@ -2533,7 +2534,7 @@ test "unlinkat" { switch (cqe.err()) { .SUCCESS => {}, // This kernel's io_uring does not yet implement unlinkat (kernel version < 5.11) - .INVAL => return error.SkipZigTest, + .BADF, .INVAL => return error.SkipZigTest, else => |errno| std.debug.panic("unhandled errno: {}", .{errno}), } try testing.expectEqual(linux.io_uring_cqe{ @@ -2579,7 +2580,7 @@ test "mkdirat" { switch (cqe.err()) { .SUCCESS => {}, // This kernel's io_uring does not yet implement mkdirat (kernel version < 5.15) - .INVAL => return error.SkipZigTest, + .BADF, .INVAL => return error.SkipZigTest, else => |errno| std.debug.panic("unhandled errno: {}", .{errno}), } try testing.expectEqual(linux.io_uring_cqe{ @@ -2628,7 +2629,7 @@ test "symlinkat" { switch (cqe.err()) { .SUCCESS => {}, // This kernel's io_uring does not yet implement symlinkat (kernel version < 5.15) - .INVAL => return error.SkipZigTest, + .BADF, .INVAL => return error.SkipZigTest, else => |errno| std.debug.panic("unhandled errno: {}", .{errno}), } try testing.expectEqual(linux.io_uring_cqe{ @@ -2683,7 +2684,7 @@ test "linkat" { switch (cqe.err()) { .SUCCESS => {}, // This kernel's io_uring does not yet implement linkat (kernel version < 5.15) - .INVAL => return error.SkipZigTest, + .BADF, .INVAL => return error.SkipZigTest, else => |errno| std.debug.panic("unhandled errno: {}", .{errno}), } try testing.expectEqual(linux.io_uring_cqe{ diff --git a/zig/lib/std/os/uefi.zig b/zig/lib/std/os/uefi.zig index b4582c121d..4c034ed456 100644 --- a/zig/lib/std/os/uefi.zig +++ b/zig/lib/std/os/uefi.zig @@ -7,6 +7,13 @@ pub const protocols = @import("uefi/protocols.zig"); pub const Status = @import("uefi/status.zig").Status; pub const tables = @import("uefi/tables.zig"); +/// The memory type to allocate when using the pool +/// Defaults to .LoaderData, the default data allocation type +/// used by UEFI applications to allocate pool memory. +pub var efi_pool_memory_type: tables.MemoryType = .LoaderData; +pub const pool_allocator = @import("uefi/pool_allocator.zig").pool_allocator; +pub const raw_pool_allocator = @import("uefi/pool_allocator.zig").raw_pool_allocator; + /// The EFI image's handle that is passed to its entry point. pub var handle: Handle = undefined; diff --git a/zig/lib/std/os/uefi/pool_allocator.zig b/zig/lib/std/os/uefi/pool_allocator.zig new file mode 100644 index 0000000000..3294621a18 --- /dev/null +++ b/zig/lib/std/os/uefi/pool_allocator.zig @@ -0,0 +1,153 @@ +const std = @import("std"); + +const mem = std.mem; +const uefi = std.os.uefi; + +const assert = std.debug.assert; + +const Allocator = mem.Allocator; + +const UefiPoolAllocator = struct { + fn getHeader(ptr: [*]u8) *[*]align(8) u8 { + return @intToPtr(*[*]align(8) u8, @ptrToInt(ptr) - @sizeOf(usize)); + } + + fn alignedAlloc(len: usize, alignment: usize) ?[*]u8 { + var unaligned_ptr: [*]align(8) u8 = undefined; + + if (uefi.system_table.boot_services.?.allocatePool(uefi.efi_pool_memory_type, len, &unaligned_ptr) != .Success) + return null; + + const unaligned_addr = @ptrToInt(unaligned_ptr); + const aligned_addr = mem.alignForward(unaligned_addr + @sizeOf(usize), alignment); + + var aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr); + getHeader(aligned_ptr).* = unaligned_ptr; + + return aligned_ptr; + } + + fn alignedFree(ptr: [*]u8) void { + _ = uefi.system_table.boot_services.?.freePool(getHeader(ptr).*); + } + + fn alloc( + _: *anyopaque, + len: usize, + ptr_align: u29, + len_align: u29, + ret_addr: usize, + ) Allocator.Error![]u8 { + _ = ret_addr; + + assert(len > 0); + assert(std.math.isPowerOfTwo(ptr_align)); + + var ptr = alignedAlloc(len, ptr_align) orelse return error.OutOfMemory; + + if (len_align == 0) + return ptr[0..len]; + + return ptr[0..mem.alignBackwardAnyAlign(len, len_align)]; + } + + fn resize( + _: *anyopaque, + buf: []u8, + buf_align: u29, + new_len: usize, + len_align: u29, + ret_addr: usize, + ) ?usize { + _ = buf_align; + _ = ret_addr; + + return if (new_len <= buf.len) mem.alignAllocLen(buf.len, new_len, len_align) else null; + } + + fn free( + _: *anyopaque, + buf: []u8, + buf_align: u29, + ret_addr: usize, + ) void { + _ = buf_align; + _ = ret_addr; + alignedFree(buf.ptr); + } +}; + +/// Supports the full Allocator interface, including alignment. +/// For a direct call of `allocatePool`, see `raw_pool_allocator`. +pub const pool_allocator = Allocator{ + .ptr = undefined, + .vtable = &pool_allocator_vtable, +}; + +const pool_allocator_vtable = Allocator.VTable{ + .alloc = UefiPoolAllocator.alloc, + .resize = UefiPoolAllocator.resize, + .free = UefiPoolAllocator.free, +}; + +/// Asserts allocations are 8 byte aligned and calls `boot_services.allocatePool`. +pub const raw_pool_allocator = Allocator{ + .ptr = undefined, + .vtable = &raw_pool_allocator_table, +}; + +const raw_pool_allocator_table = Allocator.VTable{ + .alloc = uefi_alloc, + .resize = uefi_resize, + .free = uefi_free, +}; + +fn uefi_alloc( + _: *anyopaque, + len: usize, + ptr_align: u29, + len_align: u29, + ret_addr: usize, +) Allocator.Error![]u8 { + _ = len_align; + _ = ret_addr; + + std.debug.assert(ptr_align <= 8); + + var ptr: [*]align(8) u8 = undefined; + + if (uefi.system_table.boot_services.?.allocatePool(uefi.efi_pool_memory_type, len, &ptr) != .Success) { + return error.OutOfMemory; + } + + return ptr[0..len]; +} + +fn uefi_resize( + _: *anyopaque, + buf: []u8, + old_align: u29, + new_len: usize, + len_align: u29, + ret_addr: usize, +) ?usize { + _ = old_align; + _ = ret_addr; + + if (new_len <= buf.len) { + return mem.alignAllocLen(buf.len, new_len, len_align); + } + + return null; +} + +fn uefi_free( + _: *anyopaque, + buf: []u8, + buf_align: u29, + ret_addr: usize, +) void { + _ = buf_align; + _ = ret_addr; + _ = uefi.system_table.boot_services.?.freePool(@alignCast(8, buf.ptr)); +} diff --git a/zig/lib/std/os/uefi/protocols.zig b/zig/lib/std/os/uefi/protocols.zig index 353c628a05..4192b4a545 100644 --- a/zig/lib/std/os/uefi/protocols.zig +++ b/zig/lib/std/os/uefi/protocols.zig @@ -14,6 +14,7 @@ pub const MessagingDevicePath = @import("protocols/device_path_protocol.zig").Me pub const SimpleFileSystemProtocol = @import("protocols/simple_file_system_protocol.zig").SimpleFileSystemProtocol; pub const FileProtocol = @import("protocols/file_protocol.zig").FileProtocol; pub const FileInfo = @import("protocols/file_protocol.zig").FileInfo; +pub const FileSystemInfo = @import("protocols/file_protocol.zig").FileSystemInfo; pub const InputKey = @import("protocols/simple_text_input_ex_protocol.zig").InputKey; pub const KeyData = @import("protocols/simple_text_input_ex_protocol.zig").KeyData; diff --git a/zig/lib/std/os/uefi/protocols/device_path_protocol.zig b/zig/lib/std/os/uefi/protocols/device_path_protocol.zig index df59498822..df3812451c 100644 --- a/zig/lib/std/os/uefi/protocols/device_path_protocol.zig +++ b/zig/lib/std/os/uefi/protocols/device_path_protocol.zig @@ -1,4 +1,7 @@ -const uefi = @import("std").os.uefi; +const std = @import("std"); +const mem = std.mem; +const uefi = std.os.uefi; +const Allocator = mem.Allocator; const Guid = uefi.Guid; pub const DevicePathProtocol = packed struct { @@ -15,6 +18,59 @@ pub const DevicePathProtocol = packed struct { .node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b }, }; + /// Returns the next DevicePathProtocol node in the sequence, if any. + pub fn next(self: *DevicePathProtocol) ?*DevicePathProtocol { + if (self.type == .End and @intToEnum(EndDevicePath.Subtype, self.subtype) == .EndEntire) + return null; + + return @ptrCast(*DevicePathProtocol, @ptrCast([*]u8, self) + self.length); + } + + /// Calculates the total length of the device path structure in bytes, including the end of device path node. + pub fn size(self: *DevicePathProtocol) usize { + var node = self; + + while (node.next()) |next_node| { + node = next_node; + } + + return (@ptrToInt(node) + node.length) - @ptrToInt(self); + } + + /// Creates a file device path from the existing device path and a file path. + pub fn create_file_device_path(self: *DevicePathProtocol, allocator: Allocator, path: [:0]const u16) !*DevicePathProtocol { + var path_size = self.size(); + + // 2 * (path.len + 1) for the path and its null terminator, which are u16s + // DevicePathProtocol for the extra node before the end + var buf = try allocator.alloc(u8, path_size + 2 * (path.len + 1) + @sizeOf(DevicePathProtocol)); + + mem.copy(u8, buf, @ptrCast([*]const u8, self)[0..path_size]); + + // Pointer to the copy of the end node of the current chain, which is - 4 from the buffer + // as the end node itself is 4 bytes (type: u8 + subtype: u8 + length: u16). + var new = @ptrCast(*MediaDevicePath.FilePathDevicePath, buf.ptr + path_size - 4); + + new.type = .Media; + new.subtype = .FilePath; + new.length = @sizeOf(MediaDevicePath.FilePathDevicePath) + 2 * (@intCast(u16, path.len) + 1); + + // The same as new.getPath(), but not const as we're filling it in. + var ptr = @ptrCast([*:0]u16, @alignCast(2, @ptrCast([*]u8, new)) + @sizeOf(MediaDevicePath.FilePathDevicePath)); + + for (path) |s, i| + ptr[i] = s; + + ptr[path.len] = 0; + + var end = @ptrCast(*EndDevicePath.EndEntireDevicePath, @ptrCast(*DevicePathProtocol, new).next().?); + end.type = .End; + end.subtype = .EndEntire; + end.length = @sizeOf(EndDevicePath.EndEntireDevicePath); + + return @ptrCast(*DevicePathProtocol, buf.ptr); + } + pub fn getDevicePath(self: *const DevicePathProtocol) ?DevicePath { return switch (self.type) { .Hardware => blk: { diff --git a/zig/lib/std/os/uefi/protocols/file_protocol.zig b/zig/lib/std/os/uefi/protocols/file_protocol.zig index ba4fad9c75..3b53f471a9 100644 --- a/zig/lib/std/os/uefi/protocols/file_protocol.zig +++ b/zig/lib/std/os/uefi/protocols/file_protocol.zig @@ -127,15 +127,6 @@ pub const FileProtocol = extern struct { return self._flush(self); } - pub const guid align(8) = Guid{ - .time_low = 0x09576e92, - .time_mid = 0x6d3f, - .time_high_and_version = 0x11d2, - .clock_seq_high_and_reserved = 0x8e, - .clock_seq_low = 0x39, - .node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b }, - }; - pub const efi_file_mode_read: u64 = 0x0000000000000001; pub const efi_file_mode_write: u64 = 0x0000000000000002; pub const efi_file_mode_create: u64 = 0x8000000000000000; @@ -171,4 +162,35 @@ pub const FileInfo = extern struct { pub const efi_file_directory: u64 = 0x0000000000000010; pub const efi_file_archive: u64 = 0x0000000000000020; pub const efi_file_valid_attr: u64 = 0x0000000000000037; + + pub const guid align(8) = Guid{ + .time_low = 0x09576e92, + .time_mid = 0x6d3f, + .time_high_and_version = 0x11d2, + .clock_seq_high_and_reserved = 0x8e, + .clock_seq_low = 0x39, + .node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b }, + }; +}; + +pub const FileSystemInfo = extern struct { + size: u64, + read_only: bool, + volume_size: u64, + free_space: u64, + block_size: u32, + _volume_label: u16, + + pub fn getVolumeLabel(self: *const FileSystemInfo) [*:0]const u16 { + return @ptrCast([*:0]const u16, &self._volume_label); + } + + pub const guid align(8) = Guid{ + .time_low = 0x09576e93, + .time_mid = 0x6d3f, + .time_high_and_version = 0x11d2, + .clock_seq_high_and_reserved = 0x8e, + .clock_seq_low = 0x39, + .node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b }, + }; }; diff --git a/zig/lib/std/os/windows.zig b/zig/lib/std/os/windows.zig index 59e65ed54c..6b4ef5c118 100644 --- a/zig/lib/std/os/windows.zig +++ b/zig/lib/std/os/windows.zig @@ -900,6 +900,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil .FILE_IS_A_DIRECTORY => return error.IsDir, .NOT_A_DIRECTORY => return error.NotDir, .SHARING_VIOLATION => return error.FileBusy, + .CANNOT_DELETE => return error.AccessDenied, else => return unexpectedStatus(rc), } } diff --git a/zig/lib/std/pdb.zig b/zig/lib/std/pdb.zig index 0a484fed31..03f78cb179 100644 --- a/zig/lib/std/pdb.zig +++ b/zig/lib/std/pdb.zig @@ -868,7 +868,8 @@ const Msf = struct { return error.InvalidDebugInfo; if (superblock.FreeBlockMapBlock != 1 and superblock.FreeBlockMapBlock != 2) return error.InvalidDebugInfo; - if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos()) + const file_len = try file.getEndPos(); + if (superblock.NumBlocks * superblock.BlockSize != file_len) return error.InvalidDebugInfo; switch (superblock.BlockSize) { // llvm only supports 4096 but we can handle any of these values @@ -919,7 +920,7 @@ const Msf = struct { const block_id = try directory.reader().readIntLittle(u32); const n = (block_id % superblock.BlockSize); // 0 is for SuperBlock, 1 and 2 for FPMs. - if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > try file.getEndPos()) + if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > file_len) return error.InvalidBlockIndex; blocks[j] = block_id; } diff --git a/zig/lib/std/process.zig b/zig/lib/std/process.zig index 243978591b..ff1e37178f 100644 --- a/zig/lib/std/process.zig +++ b/zig/lib/std/process.zig @@ -559,9 +559,8 @@ pub fn argsAlloc(allocator: mem.Allocator) ![][:0]u8 { const contents_slice = contents.items; const slice_sizes = slice_list.items; - const contents_size_bytes = try math.add(usize, contents_slice.len, slice_sizes.len); const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len); - const total_bytes = try math.add(usize, slice_list_bytes, contents_size_bytes); + const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len); const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes); errdefer allocator.free(buf); diff --git a/zig/lib/std/start.zig b/zig/lib/std/start.zig index 1d3cad93d2..1ced6a35d8 100644 --- a/zig/lib/std/start.zig +++ b/zig/lib/std/start.zig @@ -324,7 +324,7 @@ fn _start() callconv(.Naked) noreturn { fn WinStartup() callconv(std.os.windows.WINAPI) noreturn { @setAlignStack(16); - if (!builtin.single_threaded) { + if (!builtin.single_threaded and !builtin.link_libc) { _ = @import("start_windows_tls.zig"); } @@ -335,7 +335,7 @@ fn WinStartup() callconv(std.os.windows.WINAPI) noreturn { fn wWinMainCRTStartup() callconv(std.os.windows.WINAPI) noreturn { @setAlignStack(16); - if (!builtin.single_threaded) { + if (!builtin.single_threaded and !builtin.link_libc) { _ = @import("start_windows_tls.zig"); } @@ -511,9 +511,9 @@ inline fn initEventLoopAndCallWinMain() std.os.windows.INT { }; defer loop.deinit(); - var result: u8 = undefined; - var frame: @Frame(callMainAsync) = undefined; - _ = @asyncCall(&frame, &result, callMainAsync, .{loop}); + var result: std.os.windows.INT = undefined; + var frame: @Frame(callWinMainAsync) = undefined; + _ = @asyncCall(&frame, &result, callWinMainAsync, .{loop}); loop.run(); return result; } @@ -532,6 +532,14 @@ fn callMainAsync(loop: *std.event.Loop) callconv(.Async) u8 { return callMain(); } +fn callWinMainAsync(loop: *std.event.Loop) callconv(.Async) std.os.windows.INT { + // This prevents the event loop from terminating at least until main() has returned. + // TODO This shouldn't be needed here; it should be in the event loop code. + loop.beginOneEvent(); + defer loop.finishOneEvent(); + return call_wWinMain(); +} + // This is not marked inline because it is called with @asyncCall when // there is an event loop. pub fn callMain() u8 { diff --git a/zig/lib/std/testing.zig b/zig/lib/std/testing.zig index e5c2afab40..c6a498cfff 100644 --- a/zig/lib/std/testing.zig +++ b/zig/lib/std/testing.zig @@ -406,7 +406,7 @@ pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) return; const shortened_actual = if (actual.len >= expected_ends_with.len) - actual[0..expected_ends_with.len] + actual[(actual.len - expected_ends_with.len)..] else actual; diff --git a/zig/lib/std/x/os/net.zig b/zig/lib/std/x/os/net.zig index c71bc5bd22..d4a17f8679 100644 --- a/zig/lib/std/x/os/net.zig +++ b/zig/lib/std/x/os/net.zig @@ -16,28 +16,37 @@ pub fn resolveScopeId(name: []const u8) !u32 { if (have_ifnamesize) { if (name.len >= os.IFNAMESIZE) return error.NameTooLong; - if (native_os.tag == .windows) { + if (native_os.tag == .windows or comptime native_os.tag.isDarwin()) { var interface_name: [os.IFNAMESIZE:0]u8 = undefined; mem.copy(u8, &interface_name, name); interface_name[name.len] = 0; - const rc = os.windows.ws2_32.if_nametoindex(@ptrCast([*:0]const u8, &interface_name)); + const rc = blk: { + if (native_os.tag == .windows) { + break :blk os.windows.ws2_32.if_nametoindex(@ptrCast([*:0]const u8, &interface_name)); + } else { + const index = os.system.if_nametoindex(@ptrCast([*:0]const u8, &interface_name)); + break :blk @bitCast(u32, index); + } + }; if (rc == 0) { return error.InterfaceNotFound; } return rc; } - const fd = try os.socket(os.AF.INET, os.SOCK.DGRAM, 0); - defer os.closeSocket(fd); + if (native_os.tag == .linux) { + const fd = try os.socket(os.AF.INET, os.SOCK.DGRAM, 0); + defer os.closeSocket(fd); - var f: os.ifreq = undefined; - mem.copy(u8, &f.ifrn.name, name); - f.ifrn.name[name.len] = 0; + var f: os.ifreq = undefined; + mem.copy(u8, &f.ifrn.name, name); + f.ifrn.name[name.len] = 0; - try os.ioctl_SIOCGIFINDEX(fd, &f); + try os.ioctl_SIOCGIFINDEX(fd, &f); - return @bitCast(u32, f.ifru.ivalue); + return @bitCast(u32, f.ifru.ivalue); + } } return error.InterfaceNotFound; diff --git a/zig/lib/std/zig/Ast.zig b/zig/lib/std/zig/Ast.zig index da8616ed9e..65772c87a8 100644 --- a/zig/lib/std/zig/Ast.zig +++ b/zig/lib/std/zig/Ast.zig @@ -16,7 +16,7 @@ const assert = std.debug.assert; const testing = std.testing; const mem = std.mem; const Token = std.zig.Token; -const Tree = @This(); +const Ast = @This(); pub const TokenIndex = u32; pub const ByteOffset = u32; @@ -34,7 +34,7 @@ pub const Location = struct { line_end: usize, }; -pub fn deinit(tree: *Tree, gpa: mem.Allocator) void { +pub fn deinit(tree: *Ast, gpa: mem.Allocator) void { tree.tokens.deinit(gpa); tree.nodes.deinit(gpa); gpa.free(tree.extra_data); @@ -52,7 +52,7 @@ pub const RenderError = error{ /// for allocating extra stack memory if needed, because this function utilizes recursion. /// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006. /// Caller owns the returned slice of bytes, allocated with `gpa`. -pub fn render(tree: Tree, gpa: mem.Allocator) RenderError![]u8 { +pub fn render(tree: Ast, gpa: mem.Allocator) RenderError![]u8 { var buffer = std.ArrayList(u8).init(gpa); defer buffer.deinit(); @@ -60,11 +60,11 @@ pub fn render(tree: Tree, gpa: mem.Allocator) RenderError![]u8 { return buffer.toOwnedSlice(); } -pub fn renderToArrayList(tree: Tree, buffer: *std.ArrayList(u8)) RenderError!void { +pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void { return @import("./render.zig").renderTree(buffer, tree); } -pub fn tokenLocation(self: Tree, start_offset: ByteOffset, token_index: TokenIndex) Location { +pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location { var loc = Location{ .line = 0, .column = 0, @@ -91,7 +91,7 @@ pub fn tokenLocation(self: Tree, start_offset: ByteOffset, token_index: TokenInd return loc; } -pub fn tokenSlice(tree: Tree, token_index: TokenIndex) []const u8 { +pub fn tokenSlice(tree: Ast, token_index: TokenIndex) []const u8 { const token_starts = tree.tokens.items(.start); const token_tags = tree.tokens.items(.tag); const token_tag = token_tags[token_index]; @@ -112,7 +112,7 @@ pub fn tokenSlice(tree: Tree, token_index: TokenIndex) []const u8 { return tree.source[token.loc.start..token.loc.end]; } -pub fn extraData(tree: Tree, index: usize, comptime T: type) T { +pub fn extraData(tree: Ast, index: usize, comptime T: type) T { const fields = std.meta.fields(T); var result: T = undefined; inline for (fields) |field, i| { @@ -122,13 +122,13 @@ pub fn extraData(tree: Tree, index: usize, comptime T: type) T { return result; } -pub fn rootDecls(tree: Tree) []const Node.Index { +pub fn rootDecls(tree: Ast) []const Node.Index { // Root is always index 0. const nodes_data = tree.nodes.items(.data); return tree.extra_data[nodes_data[0].lhs..nodes_data[0].rhs]; } -pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { +pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { const token_tags = tree.tokens.items(.tag); switch (parse_error.tag) { .asterisk_after_ptr_deref => { @@ -321,7 +321,7 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { } } -pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex { +pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex { const tags = tree.nodes.items(.tag); const datas = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); @@ -625,7 +625,7 @@ pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex { }; } -pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { +pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex { const tags = tree.nodes.items(.tag); const datas = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); @@ -1157,13 +1157,13 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { }; } -pub fn tokensOnSameLine(tree: Tree, token1: TokenIndex, token2: TokenIndex) bool { +pub fn tokensOnSameLine(tree: Ast, token1: TokenIndex, token2: TokenIndex) bool { const token_starts = tree.tokens.items(.start); const source = tree.source[token_starts[token1]..token_starts[token2]]; return mem.indexOfScalar(u8, source, '\n') == null; } -pub fn getNodeSource(tree: Tree, node: Node.Index) []const u8 { +pub fn getNodeSource(tree: Ast, node: Node.Index) []const u8 { const token_starts = tree.tokens.items(.start); const first_token = tree.firstToken(node); const last_token = tree.lastToken(node); @@ -1172,7 +1172,7 @@ pub fn getNodeSource(tree: Tree, node: Node.Index) []const u8 { return tree.source[start..end]; } -pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl { +pub fn globalVarDecl(tree: Ast, node: Node.Index) full.VarDecl { assert(tree.nodes.items(.tag)[node] == .global_var_decl); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.lhs, Node.GlobalVarDecl); @@ -1186,7 +1186,7 @@ pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl { }); } -pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl { +pub fn localVarDecl(tree: Ast, node: Node.Index) full.VarDecl { assert(tree.nodes.items(.tag)[node] == .local_var_decl); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.lhs, Node.LocalVarDecl); @@ -1200,7 +1200,7 @@ pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl { }); } -pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl { +pub fn simpleVarDecl(tree: Ast, node: Node.Index) full.VarDecl { assert(tree.nodes.items(.tag)[node] == .simple_var_decl); const data = tree.nodes.items(.data)[node]; return tree.fullVarDecl(.{ @@ -1213,7 +1213,7 @@ pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl { }); } -pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl { +pub fn alignedVarDecl(tree: Ast, node: Node.Index) full.VarDecl { assert(tree.nodes.items(.tag)[node] == .aligned_var_decl); const data = tree.nodes.items(.data)[node]; return tree.fullVarDecl(.{ @@ -1226,7 +1226,7 @@ pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl { }); } -pub fn ifSimple(tree: Tree, node: Node.Index) full.If { +pub fn ifSimple(tree: Ast, node: Node.Index) full.If { assert(tree.nodes.items(.tag)[node] == .if_simple); const data = tree.nodes.items(.data)[node]; return tree.fullIf(.{ @@ -1237,7 +1237,7 @@ pub fn ifSimple(tree: Tree, node: Node.Index) full.If { }); } -pub fn ifFull(tree: Tree, node: Node.Index) full.If { +pub fn ifFull(tree: Ast, node: Node.Index) full.If { assert(tree.nodes.items(.tag)[node] == .@"if"); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.If); @@ -1249,7 +1249,7 @@ pub fn ifFull(tree: Tree, node: Node.Index) full.If { }); } -pub fn containerField(tree: Tree, node: Node.Index) full.ContainerField { +pub fn containerField(tree: Ast, node: Node.Index) full.ContainerField { assert(tree.nodes.items(.tag)[node] == .container_field); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.ContainerField); @@ -1261,7 +1261,7 @@ pub fn containerField(tree: Tree, node: Node.Index) full.ContainerField { }); } -pub fn containerFieldInit(tree: Tree, node: Node.Index) full.ContainerField { +pub fn containerFieldInit(tree: Ast, node: Node.Index) full.ContainerField { assert(tree.nodes.items(.tag)[node] == .container_field_init); const data = tree.nodes.items(.data)[node]; return tree.fullContainerField(.{ @@ -1272,7 +1272,7 @@ pub fn containerFieldInit(tree: Tree, node: Node.Index) full.ContainerField { }); } -pub fn containerFieldAlign(tree: Tree, node: Node.Index) full.ContainerField { +pub fn containerFieldAlign(tree: Ast, node: Node.Index) full.ContainerField { assert(tree.nodes.items(.tag)[node] == .container_field_align); const data = tree.nodes.items(.data)[node]; return tree.fullContainerField(.{ @@ -1283,7 +1283,7 @@ pub fn containerFieldAlign(tree: Tree, node: Node.Index) full.ContainerField { }); } -pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnProto { +pub fn fnProtoSimple(tree: Ast, buffer: *[1]Node.Index, node: Node.Index) full.FnProto { assert(tree.nodes.items(.tag)[node] == .fn_proto_simple); const data = tree.nodes.items(.data)[node]; buffer[0] = data.lhs; @@ -1300,7 +1300,7 @@ pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full. }); } -pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto { +pub fn fnProtoMulti(tree: Ast, node: Node.Index) full.FnProto { assert(tree.nodes.items(.tag)[node] == .fn_proto_multi); const data = tree.nodes.items(.data)[node]; const params_range = tree.extraData(data.lhs, Node.SubRange); @@ -1317,7 +1317,7 @@ pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto { }); } -pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnProto { +pub fn fnProtoOne(tree: Ast, buffer: *[1]Node.Index, node: Node.Index) full.FnProto { assert(tree.nodes.items(.tag)[node] == .fn_proto_one); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.lhs, Node.FnProtoOne); @@ -1335,7 +1335,7 @@ pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnP }); } -pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto { +pub fn fnProto(tree: Ast, node: Node.Index) full.FnProto { assert(tree.nodes.items(.tag)[node] == .fn_proto); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.lhs, Node.FnProto); @@ -1352,7 +1352,7 @@ pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto { }); } -pub fn structInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.StructInit { +pub fn structInitOne(tree: Ast, buffer: *[1]Node.Index, node: Node.Index) full.StructInit { assert(tree.nodes.items(.tag)[node] == .struct_init_one or tree.nodes.items(.tag)[node] == .struct_init_one_comma); const data = tree.nodes.items(.data)[node]; @@ -1365,7 +1365,7 @@ pub fn structInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full. }); } -pub fn structInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.StructInit { +pub fn structInitDotTwo(tree: Ast, buffer: *[2]Node.Index, node: Node.Index) full.StructInit { assert(tree.nodes.items(.tag)[node] == .struct_init_dot_two or tree.nodes.items(.tag)[node] == .struct_init_dot_two_comma); const data = tree.nodes.items(.data)[node]; @@ -1383,7 +1383,7 @@ pub fn structInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) fu }); } -pub fn structInitDot(tree: Tree, node: Node.Index) full.StructInit { +pub fn structInitDot(tree: Ast, node: Node.Index) full.StructInit { assert(tree.nodes.items(.tag)[node] == .struct_init_dot or tree.nodes.items(.tag)[node] == .struct_init_dot_comma); const data = tree.nodes.items(.data)[node]; @@ -1394,7 +1394,7 @@ pub fn structInitDot(tree: Tree, node: Node.Index) full.StructInit { }); } -pub fn structInit(tree: Tree, node: Node.Index) full.StructInit { +pub fn structInit(tree: Ast, node: Node.Index) full.StructInit { assert(tree.nodes.items(.tag)[node] == .struct_init or tree.nodes.items(.tag)[node] == .struct_init_comma); const data = tree.nodes.items(.data)[node]; @@ -1406,7 +1406,7 @@ pub fn structInit(tree: Tree, node: Node.Index) full.StructInit { }); } -pub fn arrayInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.ArrayInit { +pub fn arrayInitOne(tree: Ast, buffer: *[1]Node.Index, node: Node.Index) full.ArrayInit { assert(tree.nodes.items(.tag)[node] == .array_init_one or tree.nodes.items(.tag)[node] == .array_init_one_comma); const data = tree.nodes.items(.data)[node]; @@ -1421,7 +1421,7 @@ pub fn arrayInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.A }; } -pub fn arrayInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ArrayInit { +pub fn arrayInitDotTwo(tree: Ast, buffer: *[2]Node.Index, node: Node.Index) full.ArrayInit { assert(tree.nodes.items(.tag)[node] == .array_init_dot_two or tree.nodes.items(.tag)[node] == .array_init_dot_two_comma); const data = tree.nodes.items(.data)[node]; @@ -1441,7 +1441,7 @@ pub fn arrayInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) ful }; } -pub fn arrayInitDot(tree: Tree, node: Node.Index) full.ArrayInit { +pub fn arrayInitDot(tree: Ast, node: Node.Index) full.ArrayInit { assert(tree.nodes.items(.tag)[node] == .array_init_dot or tree.nodes.items(.tag)[node] == .array_init_dot_comma); const data = tree.nodes.items(.data)[node]; @@ -1454,7 +1454,7 @@ pub fn arrayInitDot(tree: Tree, node: Node.Index) full.ArrayInit { }; } -pub fn arrayInit(tree: Tree, node: Node.Index) full.ArrayInit { +pub fn arrayInit(tree: Ast, node: Node.Index) full.ArrayInit { assert(tree.nodes.items(.tag)[node] == .array_init or tree.nodes.items(.tag)[node] == .array_init_comma); const data = tree.nodes.items(.data)[node]; @@ -1468,7 +1468,7 @@ pub fn arrayInit(tree: Tree, node: Node.Index) full.ArrayInit { }; } -pub fn arrayType(tree: Tree, node: Node.Index) full.ArrayType { +pub fn arrayType(tree: Ast, node: Node.Index) full.ArrayType { assert(tree.nodes.items(.tag)[node] == .array_type); const data = tree.nodes.items(.data)[node]; return .{ @@ -1481,7 +1481,7 @@ pub fn arrayType(tree: Tree, node: Node.Index) full.ArrayType { }; } -pub fn arrayTypeSentinel(tree: Tree, node: Node.Index) full.ArrayType { +pub fn arrayTypeSentinel(tree: Ast, node: Node.Index) full.ArrayType { assert(tree.nodes.items(.tag)[node] == .array_type_sentinel); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.ArrayTypeSentinel); @@ -1496,7 +1496,7 @@ pub fn arrayTypeSentinel(tree: Tree, node: Node.Index) full.ArrayType { }; } -pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType { +pub fn ptrTypeAligned(tree: Ast, node: Node.Index) full.PtrType { assert(tree.nodes.items(.tag)[node] == .ptr_type_aligned); const data = tree.nodes.items(.data)[node]; return tree.fullPtrType(.{ @@ -1510,7 +1510,7 @@ pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType { }); } -pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType { +pub fn ptrTypeSentinel(tree: Ast, node: Node.Index) full.PtrType { assert(tree.nodes.items(.tag)[node] == .ptr_type_sentinel); const data = tree.nodes.items(.data)[node]; return tree.fullPtrType(.{ @@ -1524,7 +1524,7 @@ pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType { }); } -pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType { +pub fn ptrType(tree: Ast, node: Node.Index) full.PtrType { assert(tree.nodes.items(.tag)[node] == .ptr_type); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.lhs, Node.PtrType); @@ -1539,7 +1539,7 @@ pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType { }); } -pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType { +pub fn ptrTypeBitRange(tree: Ast, node: Node.Index) full.PtrType { assert(tree.nodes.items(.tag)[node] == .ptr_type_bit_range); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.lhs, Node.PtrTypeBitRange); @@ -1554,7 +1554,7 @@ pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType { }); } -pub fn sliceOpen(tree: Tree, node: Node.Index) full.Slice { +pub fn sliceOpen(tree: Ast, node: Node.Index) full.Slice { assert(tree.nodes.items(.tag)[node] == .slice_open); const data = tree.nodes.items(.data)[node]; return .{ @@ -1568,7 +1568,7 @@ pub fn sliceOpen(tree: Tree, node: Node.Index) full.Slice { }; } -pub fn slice(tree: Tree, node: Node.Index) full.Slice { +pub fn slice(tree: Ast, node: Node.Index) full.Slice { assert(tree.nodes.items(.tag)[node] == .slice); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.Slice); @@ -1583,7 +1583,7 @@ pub fn slice(tree: Tree, node: Node.Index) full.Slice { }; } -pub fn sliceSentinel(tree: Tree, node: Node.Index) full.Slice { +pub fn sliceSentinel(tree: Ast, node: Node.Index) full.Slice { assert(tree.nodes.items(.tag)[node] == .slice_sentinel); const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.SliceSentinel); @@ -1598,7 +1598,7 @@ pub fn sliceSentinel(tree: Tree, node: Node.Index) full.Slice { }; } -pub fn containerDeclTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl { +pub fn containerDeclTwo(tree: Ast, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl { assert(tree.nodes.items(.tag)[node] == .container_decl_two or tree.nodes.items(.tag)[node] == .container_decl_two_trailing); const data = tree.nodes.items(.data)[node]; @@ -1617,7 +1617,7 @@ pub fn containerDeclTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) fu }); } -pub fn containerDecl(tree: Tree, node: Node.Index) full.ContainerDecl { +pub fn containerDecl(tree: Ast, node: Node.Index) full.ContainerDecl { assert(tree.nodes.items(.tag)[node] == .container_decl or tree.nodes.items(.tag)[node] == .container_decl_trailing); const data = tree.nodes.items(.data)[node]; @@ -1629,7 +1629,7 @@ pub fn containerDecl(tree: Tree, node: Node.Index) full.ContainerDecl { }); } -pub fn containerDeclArg(tree: Tree, node: Node.Index) full.ContainerDecl { +pub fn containerDeclArg(tree: Ast, node: Node.Index) full.ContainerDecl { assert(tree.nodes.items(.tag)[node] == .container_decl_arg or tree.nodes.items(.tag)[node] == .container_decl_arg_trailing); const data = tree.nodes.items(.data)[node]; @@ -1642,7 +1642,7 @@ pub fn containerDeclArg(tree: Tree, node: Node.Index) full.ContainerDecl { }); } -pub fn taggedUnionTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl { +pub fn taggedUnionTwo(tree: Ast, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl { assert(tree.nodes.items(.tag)[node] == .tagged_union_two or tree.nodes.items(.tag)[node] == .tagged_union_two_trailing); const data = tree.nodes.items(.data)[node]; @@ -1662,7 +1662,7 @@ pub fn taggedUnionTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full }); } -pub fn taggedUnion(tree: Tree, node: Node.Index) full.ContainerDecl { +pub fn taggedUnion(tree: Ast, node: Node.Index) full.ContainerDecl { assert(tree.nodes.items(.tag)[node] == .tagged_union or tree.nodes.items(.tag)[node] == .tagged_union_trailing); const data = tree.nodes.items(.data)[node]; @@ -1675,7 +1675,7 @@ pub fn taggedUnion(tree: Tree, node: Node.Index) full.ContainerDecl { }); } -pub fn taggedUnionEnumTag(tree: Tree, node: Node.Index) full.ContainerDecl { +pub fn taggedUnionEnumTag(tree: Ast, node: Node.Index) full.ContainerDecl { assert(tree.nodes.items(.tag)[node] == .tagged_union_enum_tag or tree.nodes.items(.tag)[node] == .tagged_union_enum_tag_trailing); const data = tree.nodes.items(.data)[node]; @@ -1689,7 +1689,7 @@ pub fn taggedUnionEnumTag(tree: Tree, node: Node.Index) full.ContainerDecl { }); } -pub fn switchCaseOne(tree: Tree, node: Node.Index) full.SwitchCase { +pub fn switchCaseOne(tree: Ast, node: Node.Index) full.SwitchCase { const data = &tree.nodes.items(.data)[node]; const values: *[1]Node.Index = &data.lhs; return tree.fullSwitchCase(.{ @@ -1699,7 +1699,7 @@ pub fn switchCaseOne(tree: Tree, node: Node.Index) full.SwitchCase { }); } -pub fn switchCase(tree: Tree, node: Node.Index) full.SwitchCase { +pub fn switchCase(tree: Ast, node: Node.Index) full.SwitchCase { const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.lhs, Node.SubRange); return tree.fullSwitchCase(.{ @@ -1709,7 +1709,7 @@ pub fn switchCase(tree: Tree, node: Node.Index) full.SwitchCase { }); } -pub fn asmSimple(tree: Tree, node: Node.Index) full.Asm { +pub fn asmSimple(tree: Ast, node: Node.Index) full.Asm { const data = tree.nodes.items(.data)[node]; return tree.fullAsm(.{ .asm_token = tree.nodes.items(.main_token)[node], @@ -1719,7 +1719,7 @@ pub fn asmSimple(tree: Tree, node: Node.Index) full.Asm { }); } -pub fn asmFull(tree: Tree, node: Node.Index) full.Asm { +pub fn asmFull(tree: Ast, node: Node.Index) full.Asm { const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.Asm); return tree.fullAsm(.{ @@ -1730,7 +1730,7 @@ pub fn asmFull(tree: Tree, node: Node.Index) full.Asm { }); } -pub fn whileSimple(tree: Tree, node: Node.Index) full.While { +pub fn whileSimple(tree: Ast, node: Node.Index) full.While { const data = tree.nodes.items(.data)[node]; return tree.fullWhile(.{ .while_token = tree.nodes.items(.main_token)[node], @@ -1741,7 +1741,7 @@ pub fn whileSimple(tree: Tree, node: Node.Index) full.While { }); } -pub fn whileCont(tree: Tree, node: Node.Index) full.While { +pub fn whileCont(tree: Ast, node: Node.Index) full.While { const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.WhileCont); return tree.fullWhile(.{ @@ -1753,7 +1753,7 @@ pub fn whileCont(tree: Tree, node: Node.Index) full.While { }); } -pub fn whileFull(tree: Tree, node: Node.Index) full.While { +pub fn whileFull(tree: Ast, node: Node.Index) full.While { const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.While); return tree.fullWhile(.{ @@ -1765,7 +1765,7 @@ pub fn whileFull(tree: Tree, node: Node.Index) full.While { }); } -pub fn forSimple(tree: Tree, node: Node.Index) full.While { +pub fn forSimple(tree: Ast, node: Node.Index) full.While { const data = tree.nodes.items(.data)[node]; return tree.fullWhile(.{ .while_token = tree.nodes.items(.main_token)[node], @@ -1776,7 +1776,7 @@ pub fn forSimple(tree: Tree, node: Node.Index) full.While { }); } -pub fn forFull(tree: Tree, node: Node.Index) full.While { +pub fn forFull(tree: Ast, node: Node.Index) full.While { const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.If); return tree.fullWhile(.{ @@ -1788,7 +1788,7 @@ pub fn forFull(tree: Tree, node: Node.Index) full.While { }); } -pub fn callOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.Call { +pub fn callOne(tree: Ast, buffer: *[1]Node.Index, node: Node.Index) full.Call { const data = tree.nodes.items(.data)[node]; buffer.* = .{data.rhs}; const params = if (data.rhs != 0) buffer[0..1] else buffer[0..0]; @@ -1799,7 +1799,7 @@ pub fn callOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.Call { }); } -pub fn callFull(tree: Tree, node: Node.Index) full.Call { +pub fn callFull(tree: Ast, node: Node.Index) full.Call { const data = tree.nodes.items(.data)[node]; const extra = tree.extraData(data.rhs, Node.SubRange); return tree.fullCall(.{ @@ -1809,7 +1809,7 @@ pub fn callFull(tree: Tree, node: Node.Index) full.Call { }); } -fn fullVarDecl(tree: Tree, info: full.VarDecl.Components) full.VarDecl { +fn fullVarDecl(tree: Ast, info: full.VarDecl.Components) full.VarDecl { const token_tags = tree.tokens.items(.tag); var result: full.VarDecl = .{ .ast = info, @@ -1834,7 +1834,7 @@ fn fullVarDecl(tree: Tree, info: full.VarDecl.Components) full.VarDecl { return result; } -fn fullIf(tree: Tree, info: full.If.Components) full.If { +fn fullIf(tree: Ast, info: full.If.Components) full.If { const token_tags = tree.tokens.items(.tag); var result: full.If = .{ .ast = info, @@ -1859,7 +1859,7 @@ fn fullIf(tree: Tree, info: full.If.Components) full.If { return result; } -fn fullContainerField(tree: Tree, info: full.ContainerField.Components) full.ContainerField { +fn fullContainerField(tree: Ast, info: full.ContainerField.Components) full.ContainerField { const token_tags = tree.tokens.items(.tag); var result: full.ContainerField = .{ .ast = info, @@ -1873,7 +1873,7 @@ fn fullContainerField(tree: Tree, info: full.ContainerField.Components) full.Con return result; } -fn fullFnProto(tree: Tree, info: full.FnProto.Components) full.FnProto { +fn fullFnProto(tree: Ast, info: full.FnProto.Components) full.FnProto { const token_tags = tree.tokens.items(.tag); var result: full.FnProto = .{ .ast = info, @@ -1909,7 +1909,7 @@ fn fullFnProto(tree: Tree, info: full.FnProto.Components) full.FnProto { return result; } -fn fullStructInit(tree: Tree, info: full.StructInit.Components) full.StructInit { +fn fullStructInit(tree: Ast, info: full.StructInit.Components) full.StructInit { _ = tree; var result: full.StructInit = .{ .ast = info, @@ -1917,7 +1917,7 @@ fn fullStructInit(tree: Tree, info: full.StructInit.Components) full.StructInit return result; } -fn fullPtrType(tree: Tree, info: full.PtrType.Components) full.PtrType { +fn fullPtrType(tree: Ast, info: full.PtrType.Components) full.PtrType { const token_tags = tree.tokens.items(.tag); // TODO: looks like stage1 isn't quite smart enough to handle enum // literals in some places here @@ -1966,7 +1966,7 @@ fn fullPtrType(tree: Tree, info: full.PtrType.Components) full.PtrType { return result; } -fn fullContainerDecl(tree: Tree, info: full.ContainerDecl.Components) full.ContainerDecl { +fn fullContainerDecl(tree: Ast, info: full.ContainerDecl.Components) full.ContainerDecl { const token_tags = tree.tokens.items(.tag); var result: full.ContainerDecl = .{ .ast = info, @@ -1979,7 +1979,7 @@ fn fullContainerDecl(tree: Tree, info: full.ContainerDecl.Components) full.Conta return result; } -fn fullSwitchCase(tree: Tree, info: full.SwitchCase.Components) full.SwitchCase { +fn fullSwitchCase(tree: Ast, info: full.SwitchCase.Components) full.SwitchCase { const token_tags = tree.tokens.items(.tag); var result: full.SwitchCase = .{ .ast = info, @@ -1991,7 +1991,7 @@ fn fullSwitchCase(tree: Tree, info: full.SwitchCase.Components) full.SwitchCase return result; } -fn fullAsm(tree: Tree, info: full.Asm.Components) full.Asm { +fn fullAsm(tree: Ast, info: full.Asm.Components) full.Asm { const token_tags = tree.tokens.items(.tag); const node_tags = tree.nodes.items(.tag); var result: full.Asm = .{ @@ -2054,7 +2054,7 @@ fn fullAsm(tree: Tree, info: full.Asm.Components) full.Asm { return result; } -fn fullWhile(tree: Tree, info: full.While.Components) full.While { +fn fullWhile(tree: Ast, info: full.While.Components) full.While { const token_tags = tree.tokens.items(.tag); var result: full.While = .{ .ast = info, @@ -2089,7 +2089,7 @@ fn fullWhile(tree: Tree, info: full.While.Components) full.While { return result; } -fn fullCall(tree: Tree, info: full.Call.Components) full.Call { +fn fullCall(tree: Ast, info: full.Call.Components) full.Call { const token_tags = tree.tokens.items(.tag); var result: full.Call = .{ .ast = info, @@ -2201,7 +2201,7 @@ pub const full = struct { /// in the params slice, since they are simple identifiers and /// not sub-expressions. pub const Iterator = struct { - tree: *const Tree, + tree: *const Ast, fn_proto: *const FnProto, param_i: usize, tok_i: TokenIndex, @@ -2291,7 +2291,7 @@ pub const full = struct { } }; - pub fn iterate(fn_proto: FnProto, tree: Tree) Iterator { + pub fn iterate(fn_proto: FnProto, tree: Ast) Iterator { return .{ .tree = &tree, .fn_proto = &fn_proto, @@ -2485,7 +2485,7 @@ pub const Node = struct { } /// Note: The FooComma/FooSemicolon variants exist to ease the implementation of - /// Tree.lastToken() + /// Ast.lastToken() pub const Tag = enum { /// sub_list[lhs...rhs] root, diff --git a/zig/lib/std/zig/parser_test.zig b/zig/lib/std/zig/parser_test.zig index 337021eaa8..066e12e558 100644 --- a/zig/lib/std/zig/parser_test.zig +++ b/zig/lib/std/zig/parser_test.zig @@ -396,6 +396,25 @@ test "zig fmt: container declaration, multiline string, add trailing comma" { ); } +test "zig fmt: container declaration, doc comment on member, add trailing comma" { + try testTransform( + \\pub const Pos = struct { + \\ /// X-axis. + \\ x: u32, + \\ /// Y-axis. + \\ y: u32 + \\}; + , + \\pub const Pos = struct { + \\ /// X-axis. + \\ x: u32, + \\ /// Y-axis. + \\ y: u32, + \\}; + \\ + ); +} + test "zig fmt: remove empty lines at start/end of container decl" { try testTransform( \\const X = struct { diff --git a/zig/lib/std/zig/render.zig b/zig/lib/std/zig/render.zig index 41e96605d2..93c9099b2e 100644 --- a/zig/lib/std/zig/render.zig +++ b/zig/lib/std/zig/render.zig @@ -1930,15 +1930,24 @@ fn renderContainerDecl( const src_has_trailing_comma = token_tags[rbrace - 1] == .comma; if (!src_has_trailing_comma) one_line: { - // We can only print all the members in-line if there are no comments or multiline strings, - // and all the members are fields. + // We print all the members in-line unless one of the following conditions are true: + + // 1. The container has comments or multiline strings. if (hasComment(tree, lbrace, rbrace) or hasMultilineString(tree, lbrace, rbrace)) { break :one_line; } + + // 2. A member of the container has a doc comment. + for (token_tags[lbrace + 1 .. rbrace - 1]) |tag| { + if (tag == .doc_comment) break :one_line; + } + + // 3. The container has non-field members. for (container_decl.ast.members) |member| { if (!node_tags[member].isContainerField()) break :one_line; } - // All the declarations on the same line. + + // Print all the declarations on the same line. try renderToken(ais, tree, lbrace, .space); // lbrace for (container_decl.ast.members) |member| { try renderMember(gpa, ais, tree, member, .space); diff --git a/zig/src/AstGen.zig b/zig/src/AstGen.zig index a3a63be09f..6035227af0 100644 --- a/zig/src/AstGen.zig +++ b/zig/src/AstGen.zig @@ -6017,6 +6017,27 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref } } +/// Parses the string `buf` as a base 10 integer of type `u16`. +/// +/// Unlike std.fmt.parseInt, does not allow the '_' character in `buf`. +fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 { + if (buf.len == 0) return error.InvalidCharacter; + + var x: u16 = 0; + + for (buf) |c| { + const digit = switch (c) { + '0'...'9' => c - '0', + else => return error.InvalidCharacter, + }; + + if (x != 0) x = try std.math.mul(u16, x, 10); + x = try std.math.add(u16, x, @as(u16, digit)); + } + + return x; +} + fn identifier( gz: *GenZir, scope: *Scope, @@ -6050,7 +6071,7 @@ fn identifier( true => .signed, false => .unsigned, }; - const bit_count = std.fmt.parseInt(u16, ident_name_raw[1..], 10) catch |err| switch (err) { + const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) { error.Overflow => return astgen.failNode( ident, "primitive integer type '{s}' exceeds maximum bit width of 65535", @@ -8864,7 +8885,7 @@ const GenZir = struct { parent: *Scope, /// All `GenZir` scopes for the same ZIR share this. astgen: *AstGen, - /// Keeps track of the list of instructions in this scope. Possibly shared. + /// Keeps track of the list of instructions in this scope. Possibly shared. /// Indexes to instructions in `astgen`. instructions: *ArrayListUnmanaged(Zir.Inst.Index), /// A sub-block may share its instructions ArrayList with containing GenZir, @@ -10098,7 +10119,7 @@ pub fn isPrimitive(name: []const u8) bool { if (name.len < 2) return false; const first_c = name[0]; if (first_c != 'i' and first_c != 'u') return false; - if (std.fmt.parseInt(u16, name[1..], 10)) |_| { + if (parseBitCount(name[1..])) |_| { return true; } else |err| switch (err) { error.Overflow => return true, diff --git a/zig/src/Compilation.zig b/zig/src/Compilation.zig index 861771def4..b44c7da78d 100644 --- a/zig/src/Compilation.zig +++ b/zig/src/Compilation.zig @@ -158,6 +158,10 @@ emit_docs: ?EmitLoc, work_queue_wait_group: WaitGroup, astgen_wait_group: WaitGroup, +/// Exported symbol names. This is only for when the target is wasm. +/// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information. +export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{}, + pub const SemaError = Module.SemaError; pub const CRTFile = struct { @@ -632,6 +636,11 @@ pub const ClangPreprocessorMode = enum { pub const SystemLib = link.SystemLib; +pub const LinkObject = struct { + path: []const u8, + must_link: bool = false, +}; + pub const InitOptions = struct { zig_lib_directory: Directory, local_cache_directory: Directory, @@ -675,7 +684,7 @@ pub const InitOptions = struct { lib_dirs: []const []const u8 = &[0][]const u8{}, rpath_list: []const []const u8 = &[0][]const u8{}, c_source_files: []const CSourceFile = &[0]CSourceFile{}, - link_objects: []const []const u8 = &[0][]const u8{}, + link_objects: []LinkObject = &[0]LinkObject{}, framework_dirs: []const []const u8 = &[0][]const u8{}, frameworks: []const []const u8 = &[0][]const u8{}, system_lib_names: []const []const u8 = &.{}, @@ -761,6 +770,8 @@ pub const InitOptions = struct { /// infinite recursion. skip_linker_dependencies: bool = false, parent_compilation_link_libc: bool = false, + hash_style: link.HashStyle = .both, + entry: ?[]const u8 = null, stack_size_override: ?u64 = null, image_base_override: ?u64 = null, self_exe_path: ?[]const u8 = null, @@ -1022,7 +1033,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (options.system_lib_names.len != 0) break :x true; for (options.link_objects) |obj| { - switch (classifyFileExt(obj)) { + switch (classifyFileExt(obj.path)) { .shared_library => break :x true, else => continue, } @@ -1384,7 +1395,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (options.c_source_files.len >= 1) { hash.addBytes(options.c_source_files[0].src_path); } else if (options.link_objects.len >= 1) { - hash.addBytes(options.link_objects[0]); + hash.addBytes(options.link_objects[0].path); } const digest = hash.final(); @@ -1474,6 +1485,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .linker_optimization = linker_optimization, .major_subsystem_version = options.major_subsystem_version, .minor_subsystem_version = options.minor_subsystem_version, + .entry = options.entry, .stack_size_override = options.stack_size_override, .image_base_override = options.image_base_override, .include_compiler_rt = include_compiler_rt, @@ -1509,6 +1521,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .is_test = options.is_test, .wasi_exec_model = wasi_exec_model, .use_stage1 = use_stage1, + .hash_style = options.hash_style, .enable_link_snapshots = options.enable_link_snapshots, .native_darwin_sdk = options.native_darwin_sdk, .install_name = options.install_name, @@ -1791,6 +1804,11 @@ pub fn destroy(self: *Compilation) void { self.work_queue_wait_group.deinit(); self.astgen_wait_group.deinit(); + for (self.export_symbol_names.items) |symbol_name| { + gpa.free(symbol_name); + } + self.export_symbol_names.deinit(gpa); + // This destroys `self`. self.arena_state.promote(gpa).deinit(); } @@ -3430,7 +3448,7 @@ pub fn addCCArgs( try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple }); switch (ext) { - .c, .cpp, .m, .mm, .h => { + .c, .cpp, .m, .mm, .h, .cu => { try argv.appendSlice(&[_][]const u8{ "-nostdinc", "-fno-spell-checking", @@ -3729,6 +3747,7 @@ fn failCObjWithOwnedErrorMsg( pub const FileExt = enum { c, cpp, + cu, h, m, mm, @@ -3743,7 +3762,7 @@ pub const FileExt = enum { pub fn clangSupportsDepFile(ext: FileExt) bool { return switch (ext) { - .c, .cpp, .h, .m, .mm => true, + .c, .cpp, .h, .m, .mm, .cu => true, .ll, .bc, @@ -3774,7 +3793,8 @@ pub fn hasCppExt(filename: []const u8) bool { return mem.endsWith(u8, filename, ".C") or mem.endsWith(u8, filename, ".cc") or mem.endsWith(u8, filename, ".cpp") or - mem.endsWith(u8, filename, ".cxx"); + mem.endsWith(u8, filename, ".cxx") or + mem.endsWith(u8, filename, ".stub"); } pub fn hasObjCExt(filename: []const u8) bool { @@ -3841,6 +3861,8 @@ pub fn classifyFileExt(filename: []const u8) FileExt { return .static_library; } else if (hasObjectExt(filename)) { return .object; + } else if (mem.endsWith(u8, filename, ".cu")) { + return .cu; } else { return .unknown; } @@ -4022,7 +4044,7 @@ fn detectLibCIncludeDirs( } fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const LibCInstallation) !LibCDirs { - var list = try std.ArrayList([]const u8).initCapacity(arena, 4); + var list = try std.ArrayList([]const u8).initCapacity(arena, 5); list.appendAssumeCapacity(lci.include_dir.?); @@ -4042,6 +4064,9 @@ fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const const include_dir_path = lci.include_dir orelse return error.LibCInstallationNotAvailable; const os_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_path, "os" }); list.appendAssumeCapacity(os_dir); + // Errors.h + const os_support_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_path, "os/support" }); + list.appendAssumeCapacity(os_support_dir); const config_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_path, "config" }); list.appendAssumeCapacity(config_dir); diff --git a/zig/src/Sema.zig b/zig/src/Sema.zig index 044084a349..67dbcb6e99 100644 --- a/zig/src/Sema.zig +++ b/zig/src/Sema.zig @@ -5145,11 +5145,6 @@ fn funcCommon( if (opt_lib_name) |lib_name| blk: { const lib_name_src: LazySrcLoc = .{ .node_offset_lib_name = src_node_offset }; log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); - mod.comp.stage1AddLinkLib(lib_name) catch |err| { - return sema.fail(block, lib_name_src, "unable to add link lib '{s}': {s}", .{ - lib_name, @errorName(err), - }); - }; const target = mod.getTarget(); if (target_util.is_libc_lib_name(target, lib_name)) { if (!mod.comp.bin_file.options.link_libc) { @@ -5160,6 +5155,7 @@ fn funcCommon( .{}, ); } + mod.comp.bin_file.options.link_libc = true; break :blk; } if (target_util.is_libcpp_lib_name(target, lib_name)) { @@ -5171,6 +5167,11 @@ fn funcCommon( .{}, ); } + mod.comp.bin_file.options.link_libcpp = true; + break :blk; + } + if (mem.eql(u8, lib_name, "unwind")) { + mod.comp.bin_file.options.link_libunwind = true; break :blk; } if (!target.isWasm() and !mod.comp.bin_file.options.pic) { @@ -5181,6 +5182,11 @@ fn funcCommon( .{ lib_name, lib_name }, ); } + mod.comp.stage1AddLinkLib(lib_name) catch |err| { + return sema.fail(block, lib_name_src, "unable to add link lib '{s}': {s}", .{ + lib_name, @errorName(err), + }); + }; } if (is_extern) { diff --git a/zig/src/arch/x86_64/abi.zig b/zig/src/arch/x86_64/abi.zig index a6c71d398f..b0ab1acefd 100644 --- a/zig/src/arch/x86_64/abi.zig +++ b/zig/src/arch/x86_64/abi.zig @@ -18,10 +18,34 @@ pub fn classifyWindows(ty: Type, target: Target) Class { else => return .memory, } return switch (ty.zigTypeTag()) { - .Int, .Bool, .Enum, .Void, .NoReturn, .ErrorSet, .Struct, .Union => .integer, - .Optional => if (ty.isPtrLikeOptional()) return .integer else return .memory, + .Pointer, + .Int, + .Bool, + .Enum, + .Void, + .NoReturn, + .ErrorSet, + .Struct, + .Union, + .Optional, + .Array, + .ErrorUnion, + .AnyFrame, + .Frame, + => .integer, + .Float, .Vector => .sse, - else => unreachable, + + .Type, + .ComptimeFloat, + .ComptimeInt, + .Undefined, + .Null, + .BoundFn, + .Fn, + .Opaque, + .EnumLiteral, + => unreachable, }; } diff --git a/zig/src/clang_options_data.zig b/zig/src/clang_options_data.zig index 3c4c084976..dbcf0f749f 100644 --- a/zig/src/clang_options_data.zig +++ b/zig/src/clang_options_data.zig @@ -1655,7 +1655,7 @@ flagpsl("MT"), .{ .name = "entry", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .entry, .pd1 = false, .pd2 = true, .psl = false, @@ -1983,7 +1983,7 @@ flagpsl("MT"), .{ .name = "sysroot", .syntax = .separate, - .zig_equivalent = .other, + .zig_equivalent = .sysroot, .pd1 = false, .pd2 = true, .psl = false, @@ -5970,7 +5970,7 @@ jspd1("undefined"), .{ .name = "sysroot=", .syntax = .joined, - .zig_equivalent = .other, + .zig_equivalent = .sysroot, .pd1 = false, .pd2 = true, .psl = false, @@ -6701,7 +6701,14 @@ joinpd1("Z"), joinpd1("a"), jspd1("b"), joinpd1("d"), -jspd1("e"), +.{ + .name = "e", + .syntax = .joined_or_separate, + .zig_equivalent = .entry, + .pd1 = true, + .pd2 = false, + .psl = false, +}, .{ .name = "l", .syntax = .joined_or_separate, diff --git a/zig/src/crash_report.zig b/zig/src/crash_report.zig index 88b59e8952..7e72c64800 100644 --- a/zig/src/crash_report.zig +++ b/zig/src/crash_report.zig @@ -4,6 +4,7 @@ const debug = std.debug; const os = std.os; const io = std.io; const print_zir = @import("print_zir.zig"); +const native_os = builtin.os.tag; const Module = @import("Module.zig"); const Sema = @import("Sema.zig"); @@ -169,7 +170,7 @@ pub fn attachSegfaultHandler() void { return; } var act = os.Sigaction{ - .handler = .{ .sigaction = handleSegfaultLinux }, + .handler = .{ .sigaction = handleSegfaultPosix }, .mask = os.empty_sigset, .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND), }; @@ -179,17 +180,17 @@ pub fn attachSegfaultHandler() void { os.sigaction(os.SIG.BUS, &act, null); } -fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn { +fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn { // TODO: use alarm() here to prevent infinite loops PanicSwitch.preDispatch(); const addr = switch (builtin.os.tag) { .linux => @ptrToInt(info.fields.sigfault.addr), - .freebsd => @ptrToInt(info.addr), + .freebsd, .macos => @ptrToInt(info.addr), .netbsd => @ptrToInt(info.info.reason.fault.addr), .openbsd => @ptrToInt(info.data.fault.addr), .solaris => @ptrToInt(info.reason.fault.addr), - else => @compileError("TODO implement handleSegfaultLinux for new linux OS"), + else => @compileError("TODO implement handleSegfaultPosix for new POSIX OS"), }; var err_buffer: [128]u8 = undefined; @@ -213,12 +214,14 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]), .freebsd => @intCast(usize, ctx.mcontext.rip), .openbsd => @intCast(usize, ctx.sc_rip), + .macos => @intCast(usize, ctx.mcontext.ss.rip), else => unreachable, }; const bp = switch (builtin.os.tag) { .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]), .openbsd => @intCast(usize, ctx.sc_rbp), .freebsd => @intCast(usize, ctx.mcontext.rbp), + .macos => @intCast(usize, ctx.mcontext.ss.rbp), else => unreachable, }; break :ctx StackContext{ .exception = .{ .bp = bp, .ip = ip } }; @@ -231,9 +234,15 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any }, .aarch64 => ctx: { const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); - const ip = @intCast(usize, ctx.mcontext.pc); + const ip = switch (native_os) { + .macos => @intCast(usize, ctx.mcontext.ss.pc), + else => @intCast(usize, ctx.mcontext.pc), + }; // x29 is the ABI-designated frame pointer - const bp = @intCast(usize, ctx.mcontext.regs[29]); + const bp = switch (native_os) { + .macos => @intCast(usize, ctx.mcontext.ss.fp), + else => @intCast(usize, ctx.mcontext.regs[29]), + }; break :ctx StackContext{ .exception = .{ .bp = bp, .ip = ip } }; }, else => .not_supported, diff --git a/zig/src/glibc.zig b/zig/src/glibc.zig index e9c0651fdc..53d40f29eb 100644 --- a/zig/src/glibc.zig +++ b/zig/src/glibc.zig @@ -182,6 +182,10 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); + const target = comp.getTarget(); + const target_ver = target.os.version_range.linux.glibc; + const start_old_init_fini = target_ver.order(.{ .major = 2, .minor = 33 }) != .gt; + switch (crt_file) { .crti_o => { var args = std.ArrayList([]const u8).init(arena); @@ -242,8 +246,9 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { "-DASSEMBLER", "-Wa,--noexecstack", }); + const src_path = if (start_old_init_fini) "start-2.33.S" else "start.S"; break :blk .{ - .src_path = try start_asm_path(comp, arena, "start.S"), + .src_path = try start_asm_path(comp, arena, src_path), .extra_flags = args.items, }; }; @@ -269,7 +274,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { return comp.build_crt_file("Scrt1", .Obj, &[_]Compilation.CSourceFile{ start_os, abi_note_o }); }, .libc_nonshared_a => { - const target = comp.getTarget(); const s = path.sep_str; const linux_prefix = lib_libc_glibc ++ "sysdeps" ++ s ++ "unix" ++ s ++ "sysv" ++ s ++ "linux" ++ s; @@ -277,6 +281,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { const Dep = struct { path: []const u8, flavor: Flavor = .shared, + exclude: bool = false, }; const deps = [_]Dep{ .{ @@ -296,6 +301,10 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { .flavor = .nonshared, }, .{ .path = lib_libc_glibc ++ "csu" ++ s ++ "errno.c" }, + .{ + .path = lib_libc_glibc ++ "csu" ++ s ++ "elf-init-2.33.c", + .exclude = !start_old_init_fini, + }, .{ .path = linux_prefix ++ "stat.c" }, .{ .path = linux_prefix ++ "fstat.c" }, .{ .path = linux_prefix ++ "lstat.c" }, @@ -309,9 +318,12 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { .{ .path = linux_prefix ++ "stat_t64_cp.c" }, }; - var c_source_files: [deps.len]Compilation.CSourceFile = undefined; + var files_buf: [deps.len]Compilation.CSourceFile = undefined; + var files_index: usize = 0; + + for (deps) |dep| { + if (dep.exclude) continue; - for (deps) |dep, i| { var args = std.ArrayList([]const u8).init(arena); try args.appendSlice(&[_][]const u8{ "-std=gnu11", @@ -353,12 +365,14 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { shared_def, "-DTOP_NAMESPACE=glibc", }); - c_source_files[i] = .{ + files_buf[files_index] = .{ .src_path = try lib_path(comp, arena, dep.path), .extra_flags = args.items, }; + files_index += 1; } - return comp.build_crt_file("c_nonshared", .Lib, &c_source_files); + const files = files_buf[0..files_index]; + return comp.build_crt_file("c_nonshared", .Lib, files); }, } } diff --git a/zig/src/libcxx.zig b/zig/src/libcxx.zig index fe96207c48..0127ad5114 100644 --- a/zig/src/libcxx.zig +++ b/zig/src/libcxx.zig @@ -43,7 +43,9 @@ const libcxx_files = [_][]const u8{ "src/exception.cpp", "src/experimental/memory_resource.cpp", "src/filesystem/directory_iterator.cpp", - "src/filesystem/int128_builtins.cpp", + // omit int128_builtins.cpp because it provides __muloti4 which is already provided + // by compiler_rt and crashes on Windows x86_64: https://github.com/ziglang/zig/issues/10719 + //"src/filesystem/int128_builtins.cpp", "src/filesystem/operations.cpp", "src/format.cpp", "src/functional.cpp", @@ -114,8 +116,8 @@ pub fn buildLibCXX(comp: *Compilation) !void { for (libcxx_files) |cxx_src| { var cflags = std.ArrayList([]const u8).init(arena); - if (target.os.tag == .windows or target.os.tag == .wasi) { - // Filesystem stuff isn't supported on WASI and Windows. + if ((target.os.tag == .windows and target.abi == .msvc) or target.os.tag == .wasi) { + // Filesystem stuff isn't supported on WASI and Windows (MSVC). if (std.mem.startsWith(u8, cxx_src, "src/filesystem/")) continue; } diff --git a/zig/src/link.zig b/zig/src/link.zig index 70e360d373..7123cc8c09 100644 --- a/zig/src/link.zig +++ b/zig/src/link.zig @@ -68,6 +68,7 @@ pub const Options = struct { /// the binary file does not already have such a section. program_code_size_hint: u64 = 256 * 1024, entry_addr: ?u64 = null, + entry: ?[]const u8, stack_size_override: ?u64, image_base_override: ?u64, include_compiler_rt: bool, @@ -126,6 +127,7 @@ pub const Options = struct { disable_lld_caching: bool, is_test: bool, use_stage1: bool, + hash_style: HashStyle, major_subsystem_version: ?u32, minor_subsystem_version: ?u32, gc_sections: ?bool = null, @@ -136,7 +138,7 @@ pub const Options = struct { soname: ?[]const u8, llvm_cpu_features: ?[*:0]const u8, - objects: []const []const u8, + objects: []Compilation.LinkObject, framework_dirs: []const []const u8, frameworks: []const []const u8, system_libs: std.StringArrayHashMapUnmanaged(SystemLib), @@ -165,6 +167,8 @@ pub const Options = struct { } }; +pub const HashStyle = enum { sysv, gnu, both }; + pub const File = struct { tag: Tag, options: Options, @@ -682,7 +686,10 @@ pub const File = struct { // We are about to obtain this lock, so here we give other processes a chance first. base.releaseLock(); - try man.addListOfFiles(base.options.objects); + for (base.options.objects) |obj| { + _ = try man.addFile(obj.path, null); + man.hash.add(obj.must_link); + } for (comp.c_object_table.keys()) |key| { _ = try man.addFile(key.status.success.object_path, null); } @@ -719,8 +726,8 @@ pub const File = struct { var object_files = try std.ArrayList([*:0]const u8).initCapacity(base.allocator, num_object_files); defer object_files.deinit(); - for (base.options.objects) |obj_path| { - object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj_path)); + for (base.options.objects) |obj| { + object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj.path)); } for (comp.c_object_table.keys()) |key| { object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.object_path)); diff --git a/zig/src/link/Coff.zig b/zig/src/link/Coff.zig index 2445b11caf..300fe4f547 100644 --- a/zig/src/link/Coff.zig +++ b/zig/src/link/Coff.zig @@ -920,11 +920,15 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { man = comp.cache_parent.obtain(); self.base.releaseLock(); - try man.addListOfFiles(self.base.options.objects); + for (self.base.options.objects) |obj| { + _ = try man.addFile(obj.path, null); + man.hash.add(obj.must_link); + } for (comp.c_object_table.keys()) |key| { _ = try man.addFile(key.status.success.object_path, null); } try man.addOptionalFile(module_obj_path); + man.hash.addOptionalBytes(self.base.options.entry); man.hash.addOptional(self.base.options.stack_size_override); man.hash.addOptional(self.base.options.image_base_override); man.hash.addListOfBytes(self.base.options.lib_dirs); @@ -945,6 +949,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { man.hash.add(self.base.options.tsaware); man.hash.add(self.base.options.nxcompat); man.hash.add(self.base.options.dynamicbase); + // strip does not need to go into the linker hash because it is part of the hash namespace man.hash.addOptional(self.base.options.major_subsystem_version); man.hash.addOptional(self.base.options.minor_subsystem_version); @@ -983,7 +988,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { if (self.base.options.objects.len != 0) - break :blk self.base.options.objects[0]; + break :blk self.base.options.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -1045,6 +1050,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { try argv.append("-DLL"); } + if (self.base.options.entry) |entry| { + try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{entry})); + } + if (self.base.options.tsaware) { try argv.append("-tsaware"); } @@ -1088,7 +1097,14 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_dir})); } - try argv.appendSlice(self.base.options.objects); + try argv.ensureUnusedCapacity(self.base.options.objects.len); + for (self.base.options.objects) |obj| { + if (obj.must_link) { + argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{s}", .{obj.path})); + } else { + argv.appendAssumeCapacity(obj.path); + } + } for (comp.c_object_table.keys()) |key| { try argv.append(key.status.success.object_path); diff --git a/zig/src/link/Elf.zig b/zig/src/link/Elf.zig index 24f8a02b95..a7fbd2aff5 100644 --- a/zig/src/link/Elf.zig +++ b/zig/src/link/Elf.zig @@ -1307,7 +1307,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { try man.addOptionalFile(self.base.options.linker_script); try man.addOptionalFile(self.base.options.version_script); - try man.addListOfFiles(self.base.options.objects); + for (self.base.options.objects) |obj| { + _ = try man.addFile(obj.path, null); + man.hash.add(obj.must_link); + } for (comp.c_object_table.keys()) |key| { _ = try man.addFile(key.status.success.object_path, null); } @@ -1316,6 +1319,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { // We can skip hashing libc and libc++ components that we are in charge of building from Zig // installation sources because they are always a product of the compiler version + target information. + man.hash.addOptionalBytes(self.base.options.entry); man.hash.add(stack_size); man.hash.addOptional(self.base.options.image_base_override); man.hash.add(gc_sections); @@ -1333,6 +1337,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { man.hash.add(self.base.options.z_noexecstack); man.hash.add(self.base.options.z_now); man.hash.add(self.base.options.z_relro); + man.hash.add(self.base.options.hash_style); + // strip does not need to go into the linker hash because it is part of the hash namespace if (self.base.options.link_libc) { man.hash.add(self.base.options.libc_installation != null); if (self.base.options.libc_installation) |libc_installation| { @@ -1391,7 +1397,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { if (self.base.options.objects.len != 0) - break :blk self.base.options.objects[0]; + break :blk self.base.options.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -1438,6 +1444,17 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { self.base.options.linker_optimization, })); + if (self.base.options.entry) |entry| { + try argv.append("--entry"); + try argv.append(entry); + } + + switch (self.base.options.hash_style) { + .gnu => try argv.append("--hash-style=gnu"), + .sysv => try argv.append("--hash-style=sysv"), + .both => {}, // this is the default + } + if (self.base.options.output_mode == .Exe) { try argv.append("-z"); try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); @@ -1468,6 +1485,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { try argv.append("--export-dynamic"); } + if (self.base.options.strip) { + try argv.append("-s"); + } + if (self.base.options.z_nodelete) { try argv.append("-z"); try argv.append("nodelete"); @@ -1601,7 +1622,21 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { } // Positional arguments to the linker such as object files. - try argv.appendSlice(self.base.options.objects); + var whole_archive = false; + for (self.base.options.objects) |obj| { + if (obj.must_link and !whole_archive) { + try argv.append("-whole-archive"); + whole_archive = true; + } else if (!obj.must_link and whole_archive) { + try argv.append("-no-whole-archive"); + whole_archive = false; + } + try argv.append(obj.path); + } + if (whole_archive) { + try argv.append("-no-whole-archive"); + whole_archive = false; + } for (comp.c_object_table.keys()) |key| { try argv.append(key.status.success.object_path); @@ -2786,7 +2821,8 @@ pub fn updateDeclExports( const stb_bits: u8 = switch (exp.options.linkage) { .Internal => elf.STB_LOCAL, .Strong => blk: { - if (mem.eql(u8, exp.options.name, "_start")) { + const entry_name = self.base.options.entry orelse "_start"; + if (mem.eql(u8, exp.options.name, entry_name)) { self.entry_addr = decl_sym.st_value; } break :blk elf.STB_GLOBAL; diff --git a/zig/src/link/MachO.zig b/zig/src/link/MachO.zig index 7dc6c52372..0653707374 100644 --- a/zig/src/link/MachO.zig +++ b/zig/src/link/MachO.zig @@ -140,8 +140,8 @@ objc_selrefs_section_index: ?u16 = null, objc_classrefs_section_index: ?u16 = null, objc_data_section_index: ?u16 = null, -bss_file_offset: u32 = 0, -tlv_bss_file_offset: u32 = 0, +rustc_section_index: ?u16 = null, +rustc_section_size: u64 = 0, locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, @@ -381,7 +381,8 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { // Adhoc code signature is required when targeting aarch64-macos either directly or indirectly via the simulator // ABI such as aarch64-ios-simulator, etc. const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator); - const needs_prealloc = !(build_options.is_stage1 and options.use_stage1); + const use_stage1 = build_options.is_stage1 and options.use_stage1; + const needs_prealloc = !use_stage1; self.* = .{ .base = .{ @@ -451,6 +452,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { const allow_undef = is_dyn_lib and (self.base.options.allow_shlib_undefined orelse false); const id_symlink_basename = "zld.id"; + const cache_dir_handle = blk: { + if (use_stage1) { + break :blk directory.handle; + } + if (self.base.options.module) |module| { + break :blk module.zig_cache_artifact_directory.handle; + } + break :blk directory.handle; + }; var man: Cache.Manifest = undefined; defer if (!self.base.options.disable_lld_caching) man.deinit(); @@ -466,7 +476,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { // We are about to obtain this lock, so here we give other processes a chance first. self.base.releaseLock(); - try man.addListOfFiles(self.base.options.objects); + for (self.base.options.objects) |obj| { + _ = try man.addFile(obj.path, null); + man.hash.add(obj.must_link); + } for (comp.c_object_table.keys()) |key| { _ = try man.addFile(key.status.success.object_path, null); } @@ -491,7 +504,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { var prev_digest_buf: [digest.len]u8 = undefined; const prev_digest: []u8 = Cache.readSmallFile( - directory.handle, + cache_dir_handle, id_symlink_basename, &prev_digest_buf, ) catch |err| blk: { @@ -527,7 +540,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { }); // We are about to change the output file to be different, so we invalidate the build hash now. - directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { + cache_dir_handle.deleteFile(id_symlink_basename) catch |err| switch (err) { error.FileNotFound => {}, else => |e| return e, }; @@ -539,8 +552,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { // here. TODO: think carefully about how we can avoid this redundant operation when doing // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { - if (self.base.options.objects.len != 0) - break :blk self.base.options.objects[0]; + if (self.base.options.objects.len != 0) { + break :blk self.base.options.objects[0].path; + } if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -560,7 +574,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { } else { if (use_stage1) { const sub_path = self.base.options.emit.?.sub_path; - self.base.file = try directory.handle.createFile(sub_path, .{ + self.base.file = try cache_dir_handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(self.base.options), @@ -649,8 +663,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { // Positional arguments to the linker such as object files and static archives. var positionals = std.ArrayList([]const u8).init(arena); + try positionals.ensureUnusedCapacity(self.base.options.objects.len); - try positionals.appendSlice(self.base.options.objects); + var must_link_archives = std.StringArrayHashMap(void).init(arena); + try must_link_archives.ensureUnusedCapacity(self.base.options.objects.len); + + for (self.base.options.objects) |obj| { + if (must_link_archives.contains(obj.path)) continue; + if (obj.must_link) { + _ = must_link_archives.getOrPutAssumeCapacity(obj.path); + } else { + _ = positionals.appendAssumeCapacity(obj.path); + } + } for (comp.c_object_table.keys()) |key| { try positionals.append(key.status.success.object_path); @@ -857,27 +882,21 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { try argv.append("dynamic_lookup"); } + for (must_link_archives.keys()) |lib| { + try argv.append(try std.fmt.allocPrint(arena, "-force_load {s}", .{lib})); + } + Compilation.dump_argv(argv.items); } var dependent_libs = std.fifo.LinearFifo(Dylib.Id, .Dynamic).init(self.base.allocator); defer dependent_libs.deinit(); try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs); + try self.parseAndForceLoadStaticArchives(must_link_archives.keys()); try self.parseLibs(libs.items, self.base.options.sysroot, &dependent_libs); try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs); } - if (self.bss_section_index) |idx| { - const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; - const sect = &seg.sections.items[idx]; - sect.offset = self.bss_file_offset; - } - if (self.tlv_bss_section_index) |idx| { - const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; - const sect = &seg.sections.items[idx]; - sect.offset = self.tlv_bss_file_offset; - } - try self.createMhExecuteHeaderAtom(); for (self.objects.items) |*object, object_id| { if (object.analyzed) continue; @@ -964,17 +983,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { try self.writeAtoms(); } - if (self.bss_section_index) |idx| { + if (self.rustc_section_index) |id| { const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; - const sect = &seg.sections.items[idx]; - self.bss_file_offset = sect.offset; - sect.offset = 0; - } - if (self.tlv_bss_section_index) |idx| { - const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; - const sect = &seg.sections.items[idx]; - self.tlv_bss_file_offset = sect.offset; - sect.offset = 0; + const sect = &seg.sections.items[id]; + sect.size = self.rustc_section_size; } try self.setEntryPoint(); @@ -1022,7 +1034,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { if (use_stage1 and self.base.options.disable_lld_caching) break :cache; // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. - Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { + Cache.writeSmallFile(cache_dir_handle, id_symlink_basename, &digest) catch |err| { log.debug("failed to save linking hash digest file: {s}", .{@errorName(err)}); }; // Again failure here only means an unnecessary cache miss. @@ -1166,7 +1178,7 @@ fn parseObject(self: *MachO, path: []const u8) !bool { return true; } -fn parseArchive(self: *MachO, path: []const u8) !bool { +fn parseArchive(self: *MachO, path: []const u8, force_load: bool) !bool { const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { error.FileNotFound => return false, else => |e| return e, @@ -1189,7 +1201,23 @@ fn parseArchive(self: *MachO, path: []const u8) !bool { else => |e| return e, }; - try self.archives.append(self.base.allocator, archive); + if (force_load) { + defer archive.deinit(self.base.allocator); + // Get all offsets from the ToC + var offsets = std.AutoArrayHashMap(u32, void).init(self.base.allocator); + defer offsets.deinit(); + for (archive.toc.values()) |offs| { + for (offs.items) |off| { + _ = try offsets.getOrPut(off); + } + } + for (offsets.keys()) |off| { + const object = try self.objects.addOne(self.base.allocator); + object.* = try archive.parseObject(self.base.allocator, self.base.options.target, off); + } + } else { + try self.archives.append(self.base.allocator, archive); + } return true; } @@ -1274,7 +1302,7 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const log.debug("parsing input file path '{s}'", .{full_path}); if (try self.parseObject(full_path)) continue; - if (try self.parseArchive(full_path)) continue; + if (try self.parseArchive(full_path, false)) continue; if (try self.parseDylib(full_path, .{ .syslibroot = syslibroot, .dependent_libs = dependent_libs, @@ -1284,6 +1312,21 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const } } +fn parseAndForceLoadStaticArchives(self: *MachO, files: []const []const u8) !void { + for (files) |file_name| { + const full_path = full_path: { + var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; + const path = try fs.realpath(file_name, &buffer); + break :full_path try self.base.allocator.dupe(u8, path); + }; + defer self.base.allocator.free(full_path); + log.debug("parsing and force loading static archive '{s}'", .{full_path}); + + if (try self.parseArchive(full_path, true)) continue; + log.warn("unknown filetype: expected static archive: '{s}'", .{file_name}); + } +} + fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, dependent_libs: anytype) !void { for (libs) |lib| { log.debug("parsing lib path '{s}'", .{lib}); @@ -1291,7 +1334,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, de .syslibroot = syslibroot, .dependent_libs = dependent_libs, })) continue; - if (try self.parseArchive(lib)) continue; + if (try self.parseArchive(lib, false)) continue; log.warn("unknown filetype for a library: '{s}'", .{lib}); } @@ -1857,6 +1900,24 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio .seg = self.data_segment_cmd_index.?, .sect = self.objc_data_section_index.?, }; + } else if (mem.eql(u8, sectname, ".rustc")) { + if (self.rustc_section_index == null) { + self.rustc_section_index = try self.initSection( + self.data_segment_cmd_index.?, + ".rustc", + sect.size, + sect.@"align", + .{}, + ); + // We need to preserve the section size for rustc to properly + // decompress the metadata. + self.rustc_section_size = sect.size; + } + + break :blk .{ + .seg = self.data_segment_cmd_index.?, + .sect = self.rustc_section_index.?, + }; } else { if (self.data_section_index == null) { self.data_section_index = try self.initSection( @@ -2021,6 +2082,8 @@ fn writeAllAtoms(self: *MachO) !void { const sect = seg.sections.items[match.sect]; var atom: *Atom = entry.value_ptr.*; + if (sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL) continue; + var buffer = std.ArrayList(u8).init(self.base.allocator); defer buffer.deinit(); try buffer.ensureTotalCapacity(try math.cast(usize, sect.size)); @@ -2073,6 +2136,9 @@ fn writeAtoms(self: *MachO) !void { const sect = seg.sections.items[match.sect]; var atom: *Atom = entry.value_ptr.*; + // TODO handle zerofill in stage2 + // if (sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL) continue; + log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() }); while (atom.prev) |prev| { @@ -4194,9 +4260,6 @@ fn populateMissingMetadata(self: *MachO) !void { .flags = macho.S_THREAD_LOCAL_ZEROFILL, }, ); - const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; - const sect = seg.sections.items[self.tlv_bss_section_index.?]; - self.tlv_bss_file_offset = sect.offset; } if (self.bss_section_index == null) { @@ -4211,9 +4274,6 @@ fn populateMissingMetadata(self: *MachO) !void { .flags = macho.S_ZEROFILL, }, ); - const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; - const sect = seg.sections.items[self.bss_section_index.?]; - self.bss_file_offset = sect.offset; } if (self.linkedit_segment_cmd_index == null) { @@ -4513,9 +4573,13 @@ fn allocateSegment(self: *MachO, index: u16, offset: u64) !void { // Allocate the sections according to their alignment at the beginning of the segment. var start: u64 = offset; for (seg.sections.items) |*sect, sect_id| { + const is_zerofill = sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL; + const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; const alignment = try math.powi(u32, 2, sect.@"align"); const start_aligned = mem.alignForwardGeneric(u64, start, alignment); - sect.offset = @intCast(u32, seg.inner.fileoff + start_aligned); + + // TODO handle zerofill sections in stage2 + sect.offset = if (is_zerofill and use_stage1) 0 else @intCast(u32, seg.inner.fileoff + start_aligned); sect.addr = seg.inner.vmaddr + start_aligned; // Recalculate section size given the allocated start address @@ -4542,11 +4606,15 @@ fn allocateSegment(self: *MachO, index: u16, offset: u64) !void { } else 0; start = start_aligned + sect.size; + + if (!(is_zerofill and use_stage1)) { + seg.inner.filesize = start; + } + seg.inner.vmsize = start; } - const seg_size_aligned = mem.alignForwardGeneric(u64, start, self.page_size); - seg.inner.filesize = seg_size_aligned; - seg.inner.vmsize = seg_size_aligned; + seg.inner.filesize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size); + seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.vmsize, self.page_size); } const InitSectionOpts = struct { @@ -4584,8 +4652,16 @@ fn initSection( off, off + size, }); + sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff; - sect.offset = @intCast(u32, off); + + const is_zerofill = opts.flags == macho.S_ZEROFILL or opts.flags == macho.S_THREAD_LOCAL_ZEROFILL; + const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; + + // TODO handle zerofill in stage2 + if (!(is_zerofill and use_stage1)) { + sect.offset = @intCast(u32, off); + } } const index = @intCast(u16, seg.sections.items.len); @@ -5020,6 +5096,7 @@ fn sortSections(self: *MachO) !void { // __DATA segment const indices = &[_]*?u16{ + &self.rustc_section_index, &self.la_symbol_ptr_section_index, &self.objc_const_section_index, &self.objc_selrefs_section_index, @@ -5774,7 +5851,10 @@ fn writeCodeSignaturePadding(self: *MachO) !void { const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data; - const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize; + // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file + // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271 + const fileoff = mem.alignForwardGeneric(u64, linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize, 16); + const padding = fileoff - (linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize); const needed_size = CodeSignature.calcCodeSignaturePaddingSize( self.base.options.emit.?.sub_path, fileoff, @@ -5784,7 +5864,7 @@ fn writeCodeSignaturePadding(self: *MachO) !void { code_sig_cmd.datasize = needed_size; // Advance size of __LINKEDIT segment - linkedit_segment.inner.filesize += needed_size; + linkedit_segment.inner.filesize += needed_size + padding; if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) { linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size); } diff --git a/zig/src/link/MachO/Atom.zig b/zig/src/link/MachO/Atom.zig index a2f1b385dc..2b16bc8cb0 100644 --- a/zig/src/link/MachO/Atom.zig +++ b/zig/src/link/MachO/Atom.zig @@ -419,6 +419,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC .X86_64_RELOC_BRANCH => { // TODO rewrite relocation try addStub(target, context); + addend = mem.readIntLittle(i32, self.code.items[offset..][0..4]); }, .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => { // TODO rewrite relocation @@ -1003,7 +1004,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { .X86_64_RELOC_BRANCH => { const displacement = try math.cast( i32, - @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4, + @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4 + rel.addend, ); mem.writeIntLittle(u32, self.code.items[rel.offset..][0..4], @bitCast(u32, displacement)); }, diff --git a/zig/src/link/MachO/Object.zig b/zig/src/link/MachO/Object.zig index 12ca463760..70cdda6c2f 100644 --- a/zig/src/link/MachO/Object.zig +++ b/zig/src/link/MachO/Object.zig @@ -409,7 +409,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! } else blk: { var iundefsym: usize = sorted_all_nlists.items.len; while (iundefsym > 0) : (iundefsym -= 1) { - const nlist = sorted_all_nlists.items[iundefsym]; + const nlist = sorted_all_nlists.items[iundefsym - 1]; if (nlist.nlist.sect()) break; } break :blk iundefsym; diff --git a/zig/src/link/Wasm.zig b/zig/src/link/Wasm.zig index cde0cdf890..37f9c2663d 100644 --- a/zig/src/link/Wasm.zig +++ b/zig/src/link/Wasm.zig @@ -495,9 +495,21 @@ fn setupMemory(self: *Wasm) !void { log.debug("Setting up memory layout", .{}); const page_size = 64 * 1024; const stack_size = self.base.options.stack_size_override orelse page_size * 1; - const stack_alignment = 16; - var memory_ptr: u64 = self.base.options.global_base orelse 1024; - memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment); + const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention + // Always place the stack at the start by default + // unless the user specified the global-base flag + var place_stack_first = true; + var memory_ptr: u64 = if (self.base.options.global_base) |base| blk: { + place_stack_first = false; + break :blk base; + } else 0; + + if (place_stack_first) { + memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment); + memory_ptr += stack_size; + // We always put the stack pointer global at index 0 + self.globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr)); + } var offset: u32 = @intCast(u32, memory_ptr); for (self.segments.items) |*segment, i| { @@ -511,8 +523,11 @@ fn setupMemory(self: *Wasm) !void { offset += segment.size; } - memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment); - memory_ptr += stack_size; + if (!place_stack_first) { + memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment); + memory_ptr += stack_size; + self.globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr)); + } // Setup the max amount of pages // For now we only support wasm32 by setting the maximum allowed memory size 2^32-1 @@ -555,9 +570,6 @@ fn setupMemory(self: *Wasm) !void { self.memories.limits.max = @intCast(u32, max_memory / page_size); log.debug("Maximum memory pages: {d}", .{self.memories.limits.max}); } - - // We always put the stack pointer global at index 0 - self.globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr)); } fn resetState(self: *Wasm) void { @@ -1000,18 +1012,23 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { // We are about to obtain this lock, so here we give other processes a chance first. self.base.releaseLock(); - try man.addListOfFiles(self.base.options.objects); + for (self.base.options.objects) |obj| { + _ = try man.addFile(obj.path, null); + man.hash.add(obj.must_link); + } for (comp.c_object_table.keys()) |key| { _ = try man.addFile(key.status.success.object_path, null); } try man.addOptionalFile(module_obj_path); try man.addOptionalFile(compiler_rt_path); + man.hash.addOptionalBytes(self.base.options.entry); man.hash.addOptional(self.base.options.stack_size_override); man.hash.add(self.base.options.import_memory); man.hash.addOptional(self.base.options.initial_memory); man.hash.addOptional(self.base.options.max_memory); man.hash.addOptional(self.base.options.global_base); man.hash.add(self.base.options.export_symbol_names.len); + // strip does not need to go into the linker hash because it is part of the hash namespace for (self.base.options.export_symbol_names) |symbol_name| { man.hash.addBytes(symbol_name); } @@ -1046,14 +1063,13 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { } const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); - - if (self.base.options.output_mode == .Obj) { + if (is_obj) { // LLD's WASM driver does not support the equivalent of `-r` so we do a simple file copy // here. TODO: think carefully about how we can avoid this redundant operation when doing // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { if (self.base.options.objects.len != 0) - break :blk self.base.options.objects[0]; + break :blk self.base.options.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -1092,6 +1108,10 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { try argv.append("--import-memory"); } + if (self.base.options.strip) { + try argv.append("-s"); + } + if (self.base.options.initial_memory) |initial_memory| { const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory}); try argv.append(arg); @@ -1105,16 +1125,58 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { if (self.base.options.global_base) |global_base| { const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base}); try argv.append(arg); + } else { + // We prepend it by default, so when a stack overflow happens the runtime will trap correctly, + // rather than silently overwrite all global declarations. See https://github.com/ziglang/zig/issues/4496 + // + // The user can overwrite this behavior by setting the global-base + try argv.append("--stack-first"); } + var auto_export_symbols = true; // Users are allowed to specify which symbols they want to export to the wasm host. for (self.base.options.export_symbol_names) |symbol_name| { const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); try argv.append(arg); + auto_export_symbols = false; } if (self.base.options.rdynamic) { try argv.append("--export-dynamic"); + auto_export_symbols = false; + } + + if (auto_export_symbols) { + if (self.base.options.module) |module| { + // when we use stage1, we use the exports that stage1 provided us. + // For stage2, we can directly retrieve them from the module. + const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; + if (use_stage1) { + for (comp.export_symbol_names.items) |symbol_name| { + try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name})); + } + } else { + const skip_export_non_fn = target.os.tag == .wasi and + self.base.options.wasi_exec_model == .command; + for (module.decl_exports.values()) |exports| { + for (exports) |exprt| { + if (skip_export_non_fn and exprt.exported_decl.ty.zigTypeTag() != .Fn) { + // skip exporting symbols when we're building a WASI command + // and the symbol is not a function + continue; + } + const symbol_name = exprt.exported_decl.name; + const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); + try argv.append(arg); + } + } + } + } + } + + if (self.base.options.entry) |entry| { + try argv.append("--entry"); + try argv.append(entry); } if (self.base.options.output_mode == .Exe) { @@ -1125,19 +1187,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}); try argv.append(arg); - // Put stack before globals so that stack overflow results in segfault immediately - // before corrupting globals. See https://github.com/ziglang/zig/issues/4496 - try argv.append("--stack-first"); - if (self.base.options.wasi_exec_model == .reactor) { // Reactor execution model does not have _start so lld doesn't look for it. try argv.append("--no-entry"); - // Make sure "_initialize" and other used-defined functions are exported if this is WASI reactor. - // If rdynamic is true, it will already be appended, so only verify if the user did not specify - // the flag in which case, we ensure `--export-dynamic` is called. - if (!self.base.options.rdynamic) { - try argv.append("--export-dynamic"); - } } } else { if (self.base.options.stack_size_override) |stack_size| { @@ -1145,12 +1197,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}); try argv.append(arg); } - - // Only when the user has not specified how they want to export the symbols, do we want - // to export all symbols. - if (self.base.options.export_symbol_names.len == 0 and !self.base.options.rdynamic) { - try argv.append("--export-all"); - } try argv.append("--no-entry"); // So lld doesn't look for _start. } try argv.appendSlice(&[_][]const u8{ @@ -1187,7 +1233,21 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { } // Positional arguments to the linker such as object files. - try argv.appendSlice(self.base.options.objects); + var whole_archive = false; + for (self.base.options.objects) |obj| { + if (obj.must_link and !whole_archive) { + try argv.append("-whole-archive"); + whole_archive = true; + } else if (!obj.must_link and whole_archive) { + try argv.append("-no-whole-archive"); + whole_archive = false; + } + try argv.append(obj.path); + } + if (whole_archive) { + try argv.append("-no-whole-archive"); + whole_archive = false; + } for (comp.c_object_table.keys()) |key| { try argv.append(key.status.success.object_path); diff --git a/zig/src/main.zig b/zig/src/main.zig index 61b4ebb7e9..42daa95d3a 100644 --- a/zig/src/main.zig +++ b/zig/src/main.zig @@ -294,10 +294,11 @@ const usage_build_generic = \\ .s Target-specific assembly source code \\ .S Assembly with C preprocessor (requires LLVM extensions) \\ .c C source code (requires LLVM extensions) - \\ .cxx .cc .C .cpp C++ source code (requires LLVM extensions) + \\ .cxx .cc .C .cpp .stub C++ source code (requires LLVM extensions) \\ .m Objective-C source code (requires LLVM extensions) \\ .mm Objective-C++ source code (requires LLVM extensions) \\ .bc LLVM IR Module (requires LLVM extensions) + \\ .cu Cuda source code (requires LLVM extensions) \\ \\General Options: \\ -h, --help Print this help and exit @@ -400,6 +401,7 @@ const usage_build_generic = \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) \\ --sysroot [path] Set the system root directory (usually /) \\ --version [ver] Dynamic library semver + \\ --entry [name] Set the entrypoint symbol name \\ -fsoname[=name] Override the default SONAME value \\ -fno-soname Disable emitting a SONAME \\ -fLLD Force using LLD as the linker @@ -643,6 +645,7 @@ fn buildOutputType( var linker_optimization: ?u8 = null; var test_evented_io = false; var test_no_exec = false; + var entry: ?[]const u8 = null; var stack_size_override: ?u64 = null; var image_base_override: ?u64 = null; var use_llvm: ?bool = null; @@ -670,6 +673,7 @@ fn buildOutputType( var enable_link_snapshots: bool = false; var native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null; var install_name: ?[]const u8 = null; + var hash_style: link.HashStyle = .both; // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. // This array is populated by zig cc frontend and then has to be converted to zig-style @@ -701,7 +705,7 @@ fn buildOutputType( var c_source_files = std.ArrayList(Compilation.CSourceFile).init(gpa); defer c_source_files.deinit(); - var link_objects = std.ArrayList([]const u8).init(gpa); + var link_objects = std.ArrayList(Compilation.LinkObject).init(gpa); defer link_objects.deinit(); var framework_dirs = std.ArrayList([]const u8).init(gpa); @@ -843,6 +847,10 @@ fn buildOutputType( if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); i += 1; optimize_mode_string = args[i]; + } else if (mem.eql(u8, arg, "--entry")) { + if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); + i += 1; + entry = args[i]; } else if (mem.eql(u8, arg, "--stack")) { if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); i += 1; @@ -1230,9 +1238,9 @@ fn buildOutputType( } } else switch (Compilation.classifyFileExt(arg)) { .object, .static_library, .shared_library => { - try link_objects.append(arg); + try link_objects.append(.{ .path = arg }); }, - .assembly, .c, .cpp, .h, .ll, .bc, .m, .mm => { + .assembly, .c, .cpp, .h, .ll, .bc, .m, .mm, .cu => { try c_source_files.append(.{ .src_path = arg, .extra_flags = try arena.dupe([]const u8, extra_cflags.items), @@ -1281,6 +1289,7 @@ fn buildOutputType( var it = ClangArgIterator.init(arena, all_args); var emit_llvm = false; var needed = false; + var must_link = false; var force_static_libs = false; while (it.has_next) { it.next() catch |err| { @@ -1299,9 +1308,14 @@ fn buildOutputType( .positional => { const file_ext = Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0)); switch (file_ext) { - .assembly, .c, .cpp, .ll, .bc, .h, .m, .mm => try c_source_files.append(.{ .src_path = it.only_arg }), + .assembly, .c, .cpp, .ll, .bc, .h, .m, .mm, .cu => { + try c_source_files.append(.{ .src_path = it.only_arg }); + }, .unknown, .shared_library, .object, .static_library => { - try link_objects.append(it.only_arg); + try link_objects.append(.{ + .path = it.only_arg, + .must_link = must_link, + }); }, .zig => { if (root_src_file) |other| { @@ -1366,6 +1380,14 @@ fn buildOutputType( needed = false; } else if (mem.eql(u8, linker_arg, "--no-as-needed")) { needed = true; + } else if (mem.eql(u8, linker_arg, "--whole-archive") or + mem.eql(u8, linker_arg, "-whole-archive")) + { + must_link = true; + } else if (mem.eql(u8, linker_arg, "--no-whole-archive") or + mem.eql(u8, linker_arg, "-no-whole-archive")) + { + must_link = false; } else if (mem.eql(u8, linker_arg, "-Bdynamic") or mem.eql(u8, linker_arg, "-dy") or mem.eql(u8, linker_arg, "-call_shared")) @@ -1468,6 +1490,12 @@ fn buildOutputType( fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{it.only_arg}); }; }, + .sysroot => { + sysroot = it.only_arg; + }, + .entry => { + entry = it.only_arg; + }, } } // Parse linker args. @@ -1609,6 +1637,12 @@ fn buildOutputType( fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); }; have_version = true; + } else if (mem.eql(u8, arg, "-e") or mem.eql(u8, arg, "--entry")) { + i += 1; + if (i >= linker_args.items.len) { + fatal("expected linker arg after '{s}'", .{arg}); + } + entry = linker_args.items[i]; } else if (mem.eql(u8, arg, "--stack")) { i += 1; if (i >= linker_args.items.len) { @@ -1645,6 +1679,12 @@ fn buildOutputType( // This option does not do anything. } else if (mem.eql(u8, arg, "--export-all-symbols")) { rdynamic = true; + } else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip-all") or + mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--strip-debug")) + { + // -s, --strip-all Strip all symbols + // -S, --strip-debug Strip debugging symbols + strip = true; } else if (mem.eql(u8, arg, "--start-group") or mem.eql(u8, arg, "--end-group")) { @@ -1733,6 +1773,28 @@ fn buildOutputType( fatal("expected linker arg after '{s}'", .{arg}); } install_name = linker_args.items[i]; + } else if (mem.eql(u8, arg, "-force_load")) { + i += 1; + if (i >= linker_args.items.len) { + fatal("expected linker arg after '{s}'", .{arg}); + } + try link_objects.append(.{ + .path = linker_args.items[i], + .must_link = true, + }); + } else if (mem.eql(u8, arg, "-hash-style") or + mem.eql(u8, arg, "--hash-style")) + { + i += 1; + if (i >= linker_args.items.len) { + fatal("expected linker arg after '{s}'", .{arg}); + } + const next_arg = linker_args.items[i]; + hash_style = std.meta.stringToEnum(link.HashStyle, next_arg) orelse { + fatal("expected [sysv|gnu|both] after --hash-style, found '{s}'", .{ + next_arg, + }); + }; } else { warn("unsupported linker arg: {s}", .{arg}); } @@ -1802,8 +1864,12 @@ fn buildOutputType( } }, } - if (c_source_files.items.len == 0 and link_objects.items.len == 0) { + if (c_source_files.items.len == 0 and + link_objects.items.len == 0 and + root_src_file == null) + { // For example `zig cc` and no args should print the "no input files" message. + // There could be other reasons to punt to clang, for example, --help. return punt_to_clang(arena, all_args); } }, @@ -1827,7 +1893,7 @@ fn buildOutputType( const basename = fs.path.basename(c_source_files.items[0].src_path); break :blk basename[0 .. basename.len - fs.path.extension(basename).len]; } else if (link_objects.items.len >= 1) { - const basename = fs.path.basename(link_objects.items[0]); + const basename = fs.path.basename(link_objects.items[0].path); break :blk basename[0 .. basename.len - fs.path.extension(basename).len]; } else if (emit_bin == .yes) { const basename = fs.path.basename(emit_bin.yes); @@ -1932,6 +1998,11 @@ fn buildOutputType( _ = system_libs.orderedRemove(lib_name); continue; } + if (target_util.is_compiler_rt_lib_name(target_info.target, lib_name)) { + std.log.warn("ignoring superfluous library '{s}': this dependency is fulfilled instead by compiler-rt which zig unconditionally provides", .{lib_name}); + _ = system_libs.orderedRemove(lib_name); + continue; + } if (std.fs.path.isAbsolute(lib_name)) { fatal("cannot use absolute path as a system library: {s}", .{lib_name}); } @@ -1945,6 +2016,10 @@ fn buildOutputType( i += 1; } } + // libc++ depends on libc + if (link_libcpp) { + link_libc = true; + } if (use_lld) |opt| { if (opt and cross_target.isDarwin()) { @@ -2030,7 +2105,7 @@ fn buildOutputType( test_path.items, @errorName(e), }), }; - try link_objects.append(try arena.dupe(u8, test_path.items)); + try link_objects.append(.{ .path = try arena.dupe(u8, test_path.items) }); break; } else { var search_paths = std.ArrayList(u8).init(arena); @@ -2446,6 +2521,7 @@ fn buildOutputType( .use_lld = use_lld, .use_clang = use_clang, .use_stage1 = use_stage1, + .hash_style = hash_style, .rdynamic = rdynamic, .linker_script = linker_script, .version_script = version_script, @@ -2474,6 +2550,7 @@ fn buildOutputType( .minor_subsystem_version = minor_subsystem_version, .link_eh_frame_hdr = link_eh_frame_hdr, .link_emit_relocs = link_emit_relocs, + .entry = entry, .stack_size_override = stack_size_override, .image_base_override = image_base_override, .strip = strip, @@ -4115,6 +4192,8 @@ pub const ClangArgIterator = struct { strip, exec_model, emit_llvm, + sysroot, + entry, }; const Args = struct { diff --git a/zig/src/stage1.zig b/zig/src/stage1.zig index 8263427fbe..fa094b2dde 100644 --- a/zig/src/stage1.zig +++ b/zig/src/stage1.zig @@ -464,3 +464,11 @@ export fn stage2_fetch_file( if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1); return contents.ptr; } + +export fn stage2_append_symbol(stage1: *Module, name_ptr: [*c]const u8, name_len: usize) Error { + if (name_len == 0) return Error.None; + const comp = @intToPtr(*Compilation, stage1.userdata); + const sym_name = comp.gpa.dupe(u8, name_ptr[0..name_len]) catch return Error.OutOfMemory; + comp.export_symbol_names.append(comp.gpa, sym_name) catch return Error.OutOfMemory; + return Error.None; +} diff --git a/zig/src/stage1/all_types.hpp b/zig/src/stage1/all_types.hpp index f1308f3a94..b5a7f07975 100644 --- a/zig/src/stage1/all_types.hpp +++ b/zig/src/stage1/all_types.hpp @@ -1192,7 +1192,6 @@ struct AstNodeAnyFrameType { struct AstNode { enum NodeType type; TokenIndex main_token; - bool already_traced_this_node; ZigType *owner; union { AstNodeFnDef fn_def; diff --git a/zig/src/stage1/analyze.cpp b/zig/src/stage1/analyze.cpp index 9d6f77a32d..c7756424a8 100644 --- a/zig/src/stage1/analyze.cpp +++ b/zig/src/stage1/analyze.cpp @@ -73,7 +73,6 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg } ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - node->already_traced_this_node = true; return add_token_error(g, node->owner, node->main_token, msg); } @@ -4473,11 +4472,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all break; } } - - if (g->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) { - g->trace_err = add_error_note(g, g->trace_err, source_node, buf_create_from_str("referenced here")); - source_node->already_traced_this_node = true; - } } void resolve_container_usingnamespace_decls(CodeGen *g, ScopeDecls *decls_scope) { @@ -5876,49 +5870,7 @@ static bool can_mutate_comptime_var_state(ZigValue *value) { zig_unreachable(); } -static bool return_type_is_cacheable(ZigType *return_type) { - switch (return_type->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdFn: - case ZigTypeIdOpaque: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdPointer: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return true; - - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdUnion: - return false; - - case ZigTypeIdOptional: - return return_type_is_cacheable(return_type->data.maybe.child_type); - - case ZigTypeIdErrorUnion: - return return_type_is_cacheable(return_type->data.error_union.payload_type); - } - zig_unreachable(); -} - bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { - if (!return_type_is_cacheable(return_type)) - return false; while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; @@ -8303,23 +8255,53 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents_buf) { static X64CABIClass type_windows_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 + switch (ty_size) { + case 1: + case 2: + case 4: + case 8: + break; + case 16: + return (ty->id == ZigTypeIdVector) ? X64CABIClass_SSE : X64CABIClass_MEMORY; + default: + return X64CABIClass_MEMORY; + } switch (ty->id) { - case ZigTypeIdEnum: + case ZigTypeIdInvalid: + case ZigTypeIdMetaType: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdNull: + case ZigTypeIdUndefined: + case ZigTypeIdBoundFn: + case ZigTypeIdOpaque: + case ZigTypeIdEnumLiteral: + zig_unreachable(); + + case ZigTypeIdFn: + case ZigTypeIdPointer: case ZigTypeIdInt: case ZigTypeIdBool: + case ZigTypeIdEnum: + case ZigTypeIdVoid: + case ZigTypeIdUnreachable: + case ZigTypeIdErrorSet: + case ZigTypeIdErrorUnion: + case ZigTypeIdStruct: + case ZigTypeIdUnion: + case ZigTypeIdOptional: + case ZigTypeIdFnFrame: + case ZigTypeIdAnyFrame: return X64CABIClass_INTEGER; + case ZigTypeIdFloat: case ZigTypeIdVector: return X64CABIClass_SSE; - case ZigTypeIdStruct: - case ZigTypeIdUnion: { - if (ty_size <= 8) - return X64CABIClass_INTEGER; - return X64CABIClass_MEMORY; - } - default: + + case ZigTypeIdArray: return X64CABIClass_Unknown; } + zig_unreachable(); } static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { @@ -8398,17 +8380,19 @@ static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { Error err; - const size_t ty_size = type_size(g, ty); + + if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) { + return type_windows_abi_x86_64_class(g, ty, ty_size); + } + ZigType *ptr_type; if ((err = get_codegen_ptr_type(g, ty, &ptr_type))) return X64CABIClass_Unknown; if (ptr_type != nullptr) return X64CABIClass_INTEGER; - if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) { - return type_windows_abi_x86_64_class(g, ty, ty_size); - } else if (g->zig_target->arch == ZigLLVM_aarch64 || - g->zig_target->arch == ZigLLVM_aarch64_be) + if (g->zig_target->arch == ZigLLVM_aarch64 || + g->zig_target->arch == ZigLLVM_aarch64_be) { X64CABIClass result = type_system_V_abi_x86_64_class(g, ty, ty_size); return (result == X64CABIClass_MEMORY) ? X64CABIClass_MEMORY_nobyval : result; @@ -8708,14 +8692,23 @@ static Error resolve_llvm_c_abi_type(CodeGen *g, ZigType *ty) { if (ty->data.structure.fields[i]->offset >= 8) { eightbyte_index = 1; } - X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.structure.fields[i]->type_entry); + ZigType *field_ty = ty->data.structure.fields[i]->type_entry; + X64CABIClass field_class = type_c_abi_x86_64_class(g, field_ty); if (field_class == X64CABIClass_INTEGER) { type_classes[eightbyte_index] = X64CABIClass_INTEGER; } else if (type_classes[eightbyte_index] == X64CABIClass_Unknown) { type_classes[eightbyte_index] = field_class; } - type_sizes[eightbyte_index] += ty->data.structure.fields[i]->type_entry->abi_size; + if (field_ty->abi_size > 8) { + assert(eightbyte_index == 0); + type_sizes[0] = 8; + type_sizes[1] = field_ty->abi_size - 8; + type_classes[1] = type_classes[0]; + eightbyte_index = 1; + } else { + type_sizes[eightbyte_index] += field_ty->abi_size; + } } LLVMTypeRef return_elem_types[] = { @@ -9004,8 +8997,12 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX; } - if (struct_type->abi_size <= 16 && struct_type->data.structure.layout == ContainerLayoutExtern) + if (struct_type->abi_size <= 16 && + (struct_type->data.structure.layout == ContainerLayoutExtern || + struct_type->data.structure.layout == ContainerLayoutPacked)) + { resolve_llvm_c_abi_type(g, struct_type); + } } // This is to be used instead of void for debug info types, to avoid tripping diff --git a/zig/src/stage1/bigint.cpp b/zig/src/stage1/bigint.cpp index 3a7f10e699..f027281561 100644 --- a/zig/src/stage1/bigint.cpp +++ b/zig/src/stage1/bigint.cpp @@ -219,7 +219,7 @@ void bigint_init_bigfloat(BigInt *dest, const BigFloat *op) { ui64_to_f128M(UINT64_MAX, &max_u64); if (f128M_le(&abs_val, &max_u64)) { dest->digit_count = 1; - dest->data.digit = f128M_to_ui64(&op->value, softfloat_round_minMag, false); + dest->data.digit = f128M_to_ui64(&abs_val, softfloat_round_minMag, false); bigint_normalize(dest); return; } diff --git a/zig/src/stage1/codegen.cpp b/zig/src/stage1/codegen.cpp index 335af423a8..cfd455e815 100644 --- a/zig/src/stage1/codegen.cpp +++ b/zig/src/stage1/codegen.cpp @@ -8193,7 +8193,7 @@ static void generate_error_name_table(CodeGen *g) { g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name)); - LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true); + LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), false); LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); LLVMSetInitializer(str_global, str_init); LLVMSetLinkage(str_global, LLVMPrivateLinkage); @@ -9905,6 +9905,18 @@ void codegen_build_object(CodeGen *g) { codegen_add_time_event(g, "Done"); codegen_switch_sub_prog_node(g, nullptr); + + // append all export symbols to stage2 so we can provide them to the linker + if (target_is_wasm(g->zig_target)){ + Error err; + auto export_it = g->exported_symbol_names.entry_iterator(); + decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr; + while ((curr_entry = export_it.next()) != nullptr) { + if ((err = stage2_append_symbol(&g->stage1, buf_ptr(curr_entry->key), buf_len(curr_entry->key)))) { + fprintf(stderr, "Unable to export symbol '%s': %s\n", buf_ptr(curr_entry->key), err_str(err)); + } + } + } } ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, diff --git a/zig/src/stage1/ir.cpp b/zig/src/stage1/ir.cpp index 3037717614..cc68ce0d3c 100644 --- a/zig/src/stage1/ir.cpp +++ b/zig/src/stage1/ir.cpp @@ -14982,12 +14982,16 @@ static Stage1AirInst *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, Stage1ZirI case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { + uint64_t array_len = ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len; + if (ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.sentinel != nullptr) { + array_len += 1; + } size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index; uint64_t new_index = offset + index; if (ptr_field->data.x_ptr.data.base_array.array_val->data.x_array.special != ConstArraySpecialBuf) { - if (new_index >= ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len) { + if (new_index >= array_len) { ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf("out of bounds slice")); return ira->codegen->invalid_inst_gen; } @@ -25270,13 +25274,6 @@ ZigType *ir_analyze(CodeGen *codegen, Stage1Zir *stage1_zir, Stage1Air *stage1_a } else { stage1_air->first_err_trace_msg = ira->codegen->trace_err; } - if (stage1_air->first_err_trace_msg != nullptr && - !old_instruction->source_node->already_traced_this_node) - { - old_instruction->source_node->already_traced_this_node = true; - stage1_air->first_err_trace_msg = add_error_note(ira->codegen, stage1_air->first_err_trace_msg, - old_instruction->source_node, buf_create_from_str("referenced here")); - } return ira->codegen->builtin_types.entry_invalid; } else if (ira->codegen->verbose_ir) { fprintf(stderr, "-> "); @@ -25302,13 +25299,6 @@ ZigType *ir_analyze(CodeGen *codegen, Stage1Zir *stage1_zir, Stage1Air *stage1_a ZigType *res_type; if (stage1_air->first_err_trace_msg != nullptr) { codegen->trace_err = stage1_air->first_err_trace_msg; - if (codegen->trace_err != nullptr && stage1_air->source_node != nullptr && - !stage1_air->source_node->already_traced_this_node) - { - stage1_air->source_node->already_traced_this_node = true; - codegen->trace_err = add_error_note(codegen, codegen->trace_err, - stage1_air->source_node, buf_create_from_str("referenced here")); - } res_type = ira->codegen->builtin_types.entry_invalid; } else if (ira->src_implicit_return_type_list.length == 0) { res_type = codegen->builtin_types.entry_unreachable; @@ -26273,11 +26263,6 @@ static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val) { Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val) { Error err; if ((err = ir_resolve_lazy_raw(source_node, val))) { - if (codegen->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) { - source_node->already_traced_this_node = true; - codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, - buf_create_from_str("referenced here")); - } return err; } if (type_is_invalid(val->type)) { diff --git a/zig/src/stage1/stage2.h b/zig/src/stage1/stage2.h index b7c8616ec0..58b3a7687f 100644 --- a/zig/src/stage1/stage2.h +++ b/zig/src/stage1/stage2.h @@ -182,4 +182,7 @@ ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1, const char *lib_name_ptr, size_t lib_name_len, const char *symbol_name_ptr, size_t symbol_name_len); +// ABI warning +ZIG_EXTERN_C enum Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len); + #endif diff --git a/zig/src/stage1/zig0.cpp b/zig/src/stage1/zig0.cpp index 9e15bc6e2e..439f2bd1d4 100644 --- a/zig/src/stage1/zig0.cpp +++ b/zig/src/stage1/zig0.cpp @@ -554,3 +554,8 @@ const char *stage2_version_string(void) { struct Stage2SemVer stage2_version(void) { return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH}; } + +Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len) +{ + return ErrorNone; +} diff --git a/zig/src/target.zig b/zig/src/target.zig index 8a95e756bf..aa8b078b20 100644 --- a/zig/src/target.zig +++ b/zig/src/target.zig @@ -113,7 +113,7 @@ pub fn osArchName(target: std.Target) [:0]const u8 { return switch (target.os.tag) { .linux => switch (target.cpu.arch) { .arm, .armeb, .thumb, .thumbeb => "arm", - .aarch64, .aarch64_be, .aarch64_32 => "arm64", + .aarch64, .aarch64_be, .aarch64_32 => "aarch64", .mips, .mipsel, .mips64, .mips64el => "mips", .powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc", .riscv32, .riscv64 => "riscv", @@ -427,6 +427,16 @@ pub fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool { eqlIgnoreCase(ignore_case, name, "c++abi"); } +pub fn is_compiler_rt_lib_name(target: std.Target, name: []const u8) bool { + if (target.abi.isGnu() and std.mem.eql(u8, name, "gcc_s")) { + return true; + } + if (std.mem.eql(u8, name, "compiler_rt")) { + return true; + } + return false; +} + pub fn hasDebugInfo(target: std.Target) bool { return !target.cpu.arch.isWasm(); } diff --git a/zig/src/translate_c.zig b/zig/src/translate_c.zig index 79d68ff51b..1346df7e62 100644 --- a/zig/src/translate_c.zig +++ b/zig/src/translate_c.zig @@ -4824,11 +4824,18 @@ fn qualTypeWasDemotedToOpaque(c: *Context, qt: clang.QualType) bool { fn isAnyopaque(qt: clang.QualType) bool { const ty = qt.getTypePtr(); - if (ty.getTypeClass() == .Builtin) { - const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); - return builtin_ty.getKind() == .Void; + switch (ty.getTypeClass()) { + .Builtin => { + const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); + return builtin_ty.getKind() == .Void; + }, + .Typedef => { + const typedef_ty = @ptrCast(*const clang.TypedefType, ty); + const typedef_decl = typedef_ty.getDecl(); + return isAnyopaque(typedef_decl.getUnderlyingType()); + }, + else => return false, } - return false; } const FnDeclContext = struct { @@ -5595,16 +5602,36 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { }, .FloatLiteral => |suffix| { if (suffix != .none) lit_bytes = lit_bytes[0 .. lit_bytes.len - 1]; - const dot_index = mem.indexOfScalar(u8, lit_bytes, '.').?; - if (dot_index == 0) { - lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes}); - } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isDigit(lit_bytes[dot_index + 1])) { - // If the literal lacks a digit after the `.`, we need to - // add one since `1.` or `1.e10` would be invalid syntax in Zig. - lit_bytes = try std.fmt.allocPrint(c.arena, "{s}0{s}", .{ - lit_bytes[0 .. dot_index + 1], - lit_bytes[dot_index + 1 ..], - }); + + if (lit_bytes.len >= 2 and std.ascii.eqlIgnoreCase(lit_bytes[0..2], "0x")) { + if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| { + if (dot_index == 2) { + lit_bytes = try std.fmt.allocPrint(c.arena, "0x0{s}", .{lit_bytes[2..]}); + } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isXDigit(lit_bytes[dot_index + 1])) { + // If the literal lacks a digit after the `.`, we need to + // add one since `0x1.p10` would be invalid syntax in Zig. + lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}0{s}", .{ + lit_bytes[2 .. dot_index + 1], + lit_bytes[dot_index + 1 ..], + }); + } + } + + if (lit_bytes[1] == 'X') { + // Hexadecimal with capital X, valid in C but not in Zig + lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]}); + } + } else if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| { + if (dot_index == 0) { + lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes}); + } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isDigit(lit_bytes[dot_index + 1])) { + // If the literal lacks a digit after the `.`, we need to + // add one since `1.` or `1.e10` would be invalid syntax in Zig. + lit_bytes = try std.fmt.allocPrint(c.arena, "{s}0{s}", .{ + lit_bytes[0 .. dot_index + 1], + lit_bytes[dot_index + 1 ..], + }); + } } if (suffix == .none) diff --git a/zig/test/behavior/error_stage1.zig b/zig/test/behavior/error_stage1.zig index b279927eb8..5980b23156 100644 --- a/zig/test/behavior/error_stage1.zig +++ b/zig/test/behavior/error_stage1.zig @@ -14,6 +14,17 @@ test "@errorName" { try expect(mem.eql(u8, @errorName(gimmeItBroke()), "ItBroke")); } +test "@errorName sentinel length matches slice length" { + const name = testBuiltinErrorName(error.FooBar); + const length: usize = 6; + try expectEqual(length, std.mem.indexOfSentinel(u8, 0, name.ptr)); + try expectEqual(length, name.len); +} + +pub fn testBuiltinErrorName(err: anyerror) [:0]const u8 { + return @errorName(err); +} + test "error union type " { try testErrorUnionType(); comptime try testErrorUnionType(); diff --git a/zig/test/behavior/floatop.zig b/zig/test/behavior/floatop.zig index cbf0d2532b..20ef4ce68d 100644 --- a/zig/test/behavior/floatop.zig +++ b/zig/test/behavior/floatop.zig @@ -66,3 +66,9 @@ fn testDifferentSizedFloatComparisons() !void { // try expect(@nearbyint(a) == -4); // } //} + +test "negative f128 floatToInt at compile-time" { + const a: f128 = -2; + var b = @floatToInt(i64, a); + try expect(@as(i64, -2) == b); +} diff --git a/zig/test/behavior/misc.zig b/zig/test/behavior/misc.zig index 7a248ed320..1c115073af 100644 --- a/zig/test/behavior/misc.zig +++ b/zig/test/behavior/misc.zig @@ -186,3 +186,19 @@ test "lazy typeInfo value as generic parameter" { }; S.foo(@typeInfo(@TypeOf(.{}))); } + +test "variable name containing underscores does not shadow int primitive" { + const _u0 = 0; + const i_8 = 0; + const u16_ = 0; + const i3_2 = 0; + const u6__4 = 0; + const i2_04_8 = 0; + + _ = _u0; + _ = i_8; + _ = u16_; + _ = i3_2; + _ = u6__4; + _ = i2_04_8; +} diff --git a/zig/test/behavior/slice_stage1.zig b/zig/test/behavior/slice_stage1.zig index 5bbadc3cc6..3df7a75e10 100644 --- a/zig/test/behavior/slice_stage1.zig +++ b/zig/test/behavior/slice_stage1.zig @@ -339,3 +339,21 @@ test "slice bounds in comptime concatenation" { try expect(str2.len == 1); try expect(std.mem.eql(u8, str2, "1")); } + +test "slice sentinel access at comptime" { + { + const str0 = &[_:0]u8{ '1', '2', '3' }; + const slice0: [:0]const u8 = str0; + + try expect(slice0.len == 3); + try expect(slice0[slice0.len] == 0); + } + { + const str0 = "123"; + _ = &str0[0]; + const slice0: [:0]const u8 = str0; + + try expect(slice0.len == 3); + try expect(slice0[slice0.len] == 0); + } +} diff --git a/zig/test/compile_errors.zig b/zig/test/compile_errors.zig index b1eaa03028..4b914627b5 100644 --- a/zig/test/compile_errors.zig +++ b/zig/test/compile_errors.zig @@ -412,7 +412,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:15:23: error: enum field missing: 'arst'", - "tmp.zig:27:24: note: referenced here", }); ctx.objErrStage1("field access of opaque type", @@ -505,7 +504,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions", - "tmp.zig:13:17: note: referenced here", }); ctx.objErrStage1("slice sentinel mismatch", @@ -541,7 +539,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:2:25: error: unions must have 1 or more fields", - "tmp.zig:11:17: note: referenced here", }); ctx.objErrStage1("@Type for exhaustive enum with zero fields", @@ -560,7 +557,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:2:20: error: enums must have 1 or more fields", - "tmp.zig:12:9: note: referenced here", }); ctx.objErrStage1("@Type for tagged union with extra union field", @@ -596,7 +592,6 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ "tmp.zig:14:23: error: enum field not found: 'arst'", "tmp.zig:2:20: note: enum declared here", - "tmp.zig:27:24: note: referenced here", }); ctx.objErrStage1("@Type with undefined", @@ -812,9 +807,7 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:3:35: error: unable to evaluate constant expression", - "tmp.zig:3:9: note: referenced here", "tmp.zig:7:37: error: unable to evaluate constant expression", - "tmp.zig:7:9: note: referenced here", }); ctx.objErrStage1("extern variable has no type", @@ -911,13 +904,9 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:3:32: error: unable to evaluate constant expression", - "tmp.zig:3:9: note: referenced here", "tmp.zig:7:21: error: expected float type, found 'u32'", - "tmp.zig:7:9: note: referenced here", "tmp.zig:11:26: error: expected float type, found 'u32'", - "tmp.zig:11:9: note: referenced here", "tmp.zig:15:23: error: expected integer type, found 'f32'", - "tmp.zig:15:9: note: referenced here", }); ctx.testErrStage1("invalid float casts", @@ -939,13 +928,9 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:3:36: error: unable to evaluate constant expression", - "tmp.zig:3:9: note: referenced here", "tmp.zig:7:21: error: expected integer type, found 'f32'", - "tmp.zig:7:9: note: referenced here", "tmp.zig:11:26: error: expected int type, found 'f32'", - "tmp.zig:11:9: note: referenced here", "tmp.zig:15:25: error: expected float type, found 'u32'", - "tmp.zig:15:9: note: referenced here", }); ctx.testErrStage1("invalid assignments", @@ -1218,7 +1203,6 @@ pub fn addCases(ctx: *TestContext) !void { \\export const foo = @typeInfo(@This()).Struct.decls; , &[_][]const u8{ "tmp.zig:1:20: error: dependency loop detected", - "tmp.zig:1:45: note: referenced here", }); ctx.objErrStage1("function call assigned to incorrect type", @@ -2154,7 +2138,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:2:21: error: shift amount has to be an integer type, but found '*const u8'", - "tmp.zig:2:17: note: referenced here", }); ctx.objErrStage1("bit shifting only works on integer types", @@ -2164,7 +2147,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:2:16: error: bit shifting operation expected integer type, found '*const u8'", - "tmp.zig:2:27: note: referenced here", }); ctx.objErrStage1("struct depends on itself via optional field", @@ -2461,7 +2443,6 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ "tmp.zig:4:1: error: unable to determine async function frame of 'amain'", "tmp.zig:5:10: note: analysis of function 'other' depends on the frame", - "tmp.zig:8:13: note: referenced here", }); ctx.objErrStage1("async function depends on its own frame", @@ -2474,7 +2455,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet", - "tmp.zig:5:13: note: referenced here", }); ctx.objErrStage1("non async function pointer passed to @asyncCall", @@ -2697,7 +2677,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:1:29: error: evaluation exceeded 1000 backwards branches", - "tmp.zig:5:18: note: referenced here", }); ctx.objErrStage1("@ptrToInt 0 to non optional pointer", @@ -2874,7 +2853,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:1:13: error: struct 'Foo' depends on itself", - "tmp.zig:8:28: note: referenced here", }); ctx.objErrStage1("enum field value references enum", @@ -2900,8 +2878,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:2:19: error: dependency loop detected", - "tmp.zig:1:19: note: referenced here", - "tmp.zig:4:15: note: referenced here", }); ctx.testErrStage1("not an enum type", @@ -5824,7 +5800,6 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn entry() usize { return @sizeOf(@TypeOf(y)); } , &[_][]const u8{ "tmp.zig:3:14: error: division by zero", - "tmp.zig:1:14: note: referenced here", }); ctx.objErrStage1("branch on undefined value", @@ -6205,8 +6180,6 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn entry() usize { return @sizeOf(@TypeOf(seventh_fib_number)); } , &[_][]const u8{ "tmp.zig:3:21: error: evaluation exceeded 1000 backwards branches", - "tmp.zig:1:37: note: referenced here", - "tmp.zig:6:50: note: referenced here", }); ctx.objErrStage1("@embedFile with bogus file", @@ -6243,7 +6216,6 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn entry() usize { return @sizeOf(@TypeOf(a)); } , &[_][]const u8{ "tmp.zig:6:26: error: unable to evaluate constant expression", - "tmp.zig:4:17: note: referenced here", }); ctx.objErrStage1("undeclared identifier error should mark fn as impure", @@ -6321,7 +6293,6 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn entry() usize { return @sizeOf(@TypeOf(y)); } , &[_][]const u8{ "tmp.zig:3:12: error: negation caused overflow", - "tmp.zig:1:14: note: referenced here", }); ctx.objErrStage1("add overflow in function evaluation", @@ -6333,7 +6304,6 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn entry() usize { return @sizeOf(@TypeOf(y)); } , &[_][]const u8{ "tmp.zig:3:14: error: operation caused overflow", - "tmp.zig:1:14: note: referenced here", }); ctx.objErrStage1("sub overflow in function evaluation", @@ -6345,7 +6315,6 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn entry() usize { return @sizeOf(@TypeOf(y)); } , &[_][]const u8{ "tmp.zig:3:14: error: operation caused overflow", - "tmp.zig:1:14: note: referenced here", }); ctx.objErrStage1("mul overflow in function evaluation", @@ -6357,7 +6326,6 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn entry() usize { return @sizeOf(@TypeOf(y)); } , &[_][]const u8{ "tmp.zig:3:14: error: operation caused overflow", - "tmp.zig:1:14: note: referenced here", }); ctx.objErrStage1("truncate sign mismatch", @@ -6444,7 +6412,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:3:7: error: unable to evaluate constant expression", - "tmp.zig:16:19: note: referenced here", }); ctx.objErrStage1("bogus method call on slice", @@ -6768,7 +6735,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:10:14: error: reached unreachable code", - "tmp.zig:6:20: note: referenced here", }); ctx.objErrStage1("control flow uses comptime var at runtime", @@ -7269,8 +7235,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:1:13: error: aoeu", - "tmp.zig:3:19: note: referenced here", - "tmp.zig:7:12: note: referenced here", }); ctx.objErrStage1("float literal too large error", @@ -8194,7 +8158,6 @@ pub fn addCases(ctx: *TestContext) !void { \\} , &[_][]const u8{ "tmp.zig:3:53: error: vector element type must be integer, float, bool, or pointer; '@Vector(4, u8)' is invalid", - "tmp.zig:3:16: note: referenced here", }); ctx.testErrStage1("bad @splat type", @@ -8392,7 +8355,6 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ "tmp.zig:3:42: error: unable to @bitCast from pointer type '*[2]u8'", "tmp.zig:8:32: error: destination type 'u16' has size 2 but source type '[]const u8' has size 16", - "tmp.zig:8:37: note: referenced here", }); // issue #7810 diff --git a/zig/test/run_translated_c.zig b/zig/test/run_translated_c.zig index 99ff869b11..933cf54c4f 100644 --- a/zig/test/run_translated_c.zig +++ b/zig/test/run_translated_c.zig @@ -1809,4 +1809,24 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("Typedef'ed void used as return type. Issue #10356", + \\typedef void V; + \\V foo(V *f) {} + \\int main(void) { + \\ int x = 0; + \\ foo(&x); + \\ return 0; + \\} + , ""); + + cases.add("Zero-initialization of global union. Issue #10797", + \\#include + \\union U { int x; double y; }; + \\union U u; + \\int main(void) { + \\ if (u.x != 0) abort(); + \\ return 0; + \\} + , ""); } diff --git a/zig/test/stage1/c_abi/build.zig b/zig/test/stage1/c_abi/build.zig index cf21d403f7..b9151f6dda 100644 --- a/zig/test/stage1/c_abi/build.zig +++ b/zig/test/stage1/c_abi/build.zig @@ -2,15 +2,18 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { const rel_opts = b.standardReleaseOptions(); + const target = b.standardTargetOptions(.{}); const c_obj = b.addObject("cfuncs", null); c_obj.addCSourceFile("cfuncs.c", &[_][]const u8{"-std=c99"}); c_obj.setBuildMode(rel_opts); c_obj.linkSystemLibrary("c"); + c_obj.target = target; const main = b.addTest("main.zig"); main.setBuildMode(rel_opts); main.addObject(c_obj); + main.target = target; const test_step = b.step("test", "Test the program"); test_step.dependOn(&main.step); diff --git a/zig/test/stage1/c_abi/cfuncs.c b/zig/test/stage1/c_abi/cfuncs.c index 0182462716..f5c90adba0 100644 --- a/zig/test/stage1/c_abi/cfuncs.c +++ b/zig/test/stage1/c_abi/cfuncs.c @@ -11,14 +11,24 @@ static void assert_or_panic(bool ok) { } } +struct i128 { + __int128 value; +}; + +struct u128 { + unsigned __int128 value; +}; + void zig_u8(uint8_t); void zig_u16(uint16_t); void zig_u32(uint32_t); void zig_u64(uint64_t); +void zig_struct_u128(struct u128); void zig_i8(int8_t); void zig_i16(int16_t); void zig_i32(int32_t); void zig_i64(int64_t); +void zig_struct_i128(struct i128); void zig_five_integers(int32_t, int32_t, int32_t, int32_t, int32_t); void zig_f32(float); @@ -75,6 +85,24 @@ struct MedStructMixed { void zig_med_struct_mixed(struct MedStructMixed); struct MedStructMixed zig_ret_med_struct_mixed(); +struct SmallPackedStruct { + uint8_t a: 2; + uint8_t b: 2; + uint8_t c: 2; + uint8_t d: 2; + uint8_t e: 1; +}; + +struct BigPackedStruct { + uint64_t a: 64; + uint64_t b: 64; + uint64_t c: 64; + uint64_t d: 64; + uint8_t e: 8; +}; + +//void zig_small_packed_struct(struct SmallPackedStruct); // #1481 +void zig_big_packed_struct(struct BigPackedStruct); struct SplitStructInts { uint64_t a; @@ -112,11 +140,19 @@ void run_c_tests(void) { zig_u16(0xfffe); zig_u32(0xfffffffd); zig_u64(0xfffffffffffffffc); + { + struct u128 s = {0xfffffffffffffffc}; + zig_struct_u128(s); + } zig_i8(-1); zig_i16(-2); zig_i32(-3); zig_i64(-4); + { + struct i128 s = {-6}; + zig_struct_i128(s); + } zig_five_integers(12, 34, 56, 78, 90); zig_f32(12.34f); @@ -137,6 +173,16 @@ void run_c_tests(void) { zig_small_struct_ints(s); } + { + struct BigPackedStruct s = {1, 2, 3, 4, 5}; + zig_big_packed_struct(s); + } + + { + struct SmallPackedStruct s = {0, 1, 2, 3, 1}; + //zig_small_packed_struct(s); + } + { struct SplitStructInts s = {1234, 100, 1337}; zig_split_struct_ints(s); @@ -193,6 +239,10 @@ void c_u64(uint64_t x) { assert_or_panic(x == 0xfffffffffffffffcULL); } +void c_struct_u128(struct u128 x) { + assert_or_panic(x.value == 0xfffffffffffffffcULL); +} + void c_i8(int8_t x) { assert_or_panic(x == -1); } @@ -209,6 +259,10 @@ void c_i64(int64_t x) { assert_or_panic(x == -4); } +void c_struct_i128(struct i128 x) { + assert_or_panic(x.value == -6); +} + void c_f32(float x) { assert_or_panic(x == 12.34f); } @@ -318,6 +372,44 @@ void c_split_struct_mixed(struct SplitStructMixed x) { assert_or_panic(y.c == 1337.0f); } +struct SmallPackedStruct c_ret_small_packed_struct() { + struct SmallPackedStruct s = { + .a = 0, + .b = 1, + .c = 2, + .d = 3, + .e = 1, + }; + return s; +} + +void c_small_packed_struct(struct SmallPackedStruct x) { + assert_or_panic(x.a == 0); + assert_or_panic(x.a == 1); + assert_or_panic(x.a == 2); + assert_or_panic(x.a == 3); + assert_or_panic(x.e == 1); +} + +struct BigPackedStruct c_ret_big_packed_struct() { + struct BigPackedStruct s = { + .a = 1, + .b = 2, + .c = 3, + .d = 4, + .e = 5, + }; + return s; +} + +void c_big_packed_struct(struct BigPackedStruct x) { + assert_or_panic(x.a == 1); + assert_or_panic(x.b == 2); + assert_or_panic(x.c == 3); + assert_or_panic(x.d == 4); + assert_or_panic(x.e == 5); +} + struct SplitStructMixed c_ret_split_struct_mixed() { struct SplitStructMixed s = { .a = 1234, diff --git a/zig/test/stage1/c_abi/main.zig b/zig/test/stage1/c_abi/main.zig index 40362a288e..71a53bedea 100644 --- a/zig/test/stage1/c_abi/main.zig +++ b/zig/test/stage1/c_abi/main.zig @@ -16,20 +16,22 @@ extern fn c_u8(u8) void; extern fn c_u16(u16) void; extern fn c_u32(u32) void; extern fn c_u64(u64) void; +extern fn c_struct_u128(U128) void; extern fn c_i8(i8) void; extern fn c_i16(i16) void; extern fn c_i32(i32) void; extern fn c_i64(i64) void; +extern fn c_struct_i128(I128) void; // On windows x64, the first 4 are passed via registers, others on the stack. extern fn c_five_integers(i32, i32, i32, i32, i32) void; export fn zig_five_integers(a: i32, b: i32, c: i32, d: i32, e: i32) void { - expect(a == 12) catch @panic("test failure"); - expect(b == 34) catch @panic("test failure"); - expect(c == 56) catch @panic("test failure"); - expect(d == 78) catch @panic("test failure"); - expect(e == 90) catch @panic("test failure"); + expect(a == 12) catch @panic("test failure: zig_five_integers 12"); + expect(b == 34) catch @panic("test failure: zig_five_integers 34"); + expect(c == 56) catch @panic("test failure: zig_five_integers 56"); + expect(d == 78) catch @panic("test failure: zig_five_integers 78"); + expect(e == 90) catch @panic("test failure: zig_five_integers 90"); } test "C ABI integers" { @@ -37,37 +39,52 @@ test "C ABI integers" { c_u16(0xfffe); c_u32(0xfffffffd); c_u64(0xfffffffffffffffc); + c_struct_u128(.{ .value = 0xfffffffffffffffc }); c_i8(-1); c_i16(-2); c_i32(-3); c_i64(-4); + c_struct_i128(.{ .value = -6 }); c_five_integers(12, 34, 56, 78, 90); } export fn zig_u8(x: u8) void { - expect(x == 0xff) catch @panic("test failure"); + expect(x == 0xff) catch @panic("test failure: zig_u8"); } export fn zig_u16(x: u16) void { - expect(x == 0xfffe) catch @panic("test failure"); + expect(x == 0xfffe) catch @panic("test failure: zig_u16"); } export fn zig_u32(x: u32) void { - expect(x == 0xfffffffd) catch @panic("test failure"); + expect(x == 0xfffffffd) catch @panic("test failure: zig_u32"); } export fn zig_u64(x: u64) void { - expect(x == 0xfffffffffffffffc) catch @panic("test failure"); + expect(x == 0xfffffffffffffffc) catch @panic("test failure: zig_u64"); } export fn zig_i8(x: i8) void { - expect(x == -1) catch @panic("test failure"); + expect(x == -1) catch @panic("test failure: zig_i8"); } export fn zig_i16(x: i16) void { - expect(x == -2) catch @panic("test failure"); + expect(x == -2) catch @panic("test failure: zig_i16"); } export fn zig_i32(x: i32) void { - expect(x == -3) catch @panic("test failure"); + expect(x == -3) catch @panic("test failure: zig_i32"); } export fn zig_i64(x: i64) void { - expect(x == -4) catch @panic("test failure"); + expect(x == -4) catch @panic("test failure: zig_i64"); +} + +const I128 = extern struct { + value: i128, +}; +const U128 = extern struct { + value: u128, +}; +export fn zig_struct_i128(a: I128) void { + expect(a.value == -6) catch @panic("test failure: zig_struct_i128"); +} +export fn zig_struct_u128(a: U128) void { + expect(a.value == 0xfffffffffffffffc) catch @panic("test failure: zig_struct_u128"); } extern fn c_f32(f32) void; @@ -77,11 +94,11 @@ extern fn c_f64(f64) void; extern fn c_five_floats(f32, f32, f32, f32, f32) void; export fn zig_five_floats(a: f32, b: f32, c: f32, d: f32, e: f32) void { - expect(a == 1.0) catch @panic("test failure"); - expect(b == 2.0) catch @panic("test failure"); - expect(c == 3.0) catch @panic("test failure"); - expect(d == 4.0) catch @panic("test failure"); - expect(e == 5.0) catch @panic("test failure"); + expect(a == 1.0) catch @panic("test failure: zig_five_floats 1.0"); + expect(b == 2.0) catch @panic("test failure: zig_five_floats 2.0"); + expect(c == 3.0) catch @panic("test failure: zig_five_floats 3.0"); + expect(d == 4.0) catch @panic("test failure: zig_five_floats 4.0"); + expect(e == 5.0) catch @panic("test failure: zig_five_floats 5.0"); } test "C ABI floats" { @@ -91,10 +108,10 @@ test "C ABI floats" { } export fn zig_f32(x: f32) void { - expect(x == 12.34) catch @panic("test failure"); + expect(x == 12.34) catch @panic("test failure: zig_f32"); } export fn zig_f64(x: f64) void { - expect(x == 56.78) catch @panic("test failure"); + expect(x == 56.78) catch @panic("test failure: zig_f64"); } extern fn c_ptr(*anyopaque) void; @@ -104,7 +121,7 @@ test "C ABI pointer" { } export fn zig_ptr(x: *anyopaque) void { - expect(@ptrToInt(x) == 0xdeadbeef) catch @panic("test failure"); + expect(@ptrToInt(x) == 0xdeadbeef) catch @panic("test failure: zig_ptr"); } extern fn c_bool(bool) void; @@ -114,7 +131,7 @@ test "C ABI bool" { } export fn zig_bool(x: bool) void { - expect(x) catch @panic("test failure"); + expect(x) catch @panic("test failure: zig_bool"); } const BigStruct = extern struct { @@ -138,11 +155,11 @@ test "C ABI big struct" { } export fn zig_big_struct(x: BigStruct) void { - expect(x.a == 1) catch @panic("test failure"); - expect(x.b == 2) catch @panic("test failure"); - expect(x.c == 3) catch @panic("test failure"); - expect(x.d == 4) catch @panic("test failure"); - expect(x.e == 5) catch @panic("test failure"); + expect(x.a == 1) catch @panic("test failure: zig_big_struct 1"); + expect(x.b == 2) catch @panic("test failure: zig_big_struct 2"); + expect(x.c == 3) catch @panic("test failure: zig_big_struct 3"); + expect(x.d == 4) catch @panic("test failure: zig_big_struct 4"); + expect(x.e == 5) catch @panic("test failure: zig_big_struct 5"); } const BigUnion = extern union { @@ -164,11 +181,11 @@ test "C ABI big union" { } export fn zig_big_union(x: BigUnion) void { - expect(x.a.a == 1) catch @panic("test failure"); - expect(x.a.b == 2) catch @panic("test failure"); - expect(x.a.c == 3) catch @panic("test failure"); - expect(x.a.d == 4) catch @panic("test failure"); - expect(x.a.e == 5) catch @panic("test failure"); + expect(x.a.a == 1) catch @panic("test failure: zig_big_union a"); + expect(x.a.b == 2) catch @panic("test failure: zig_big_union b"); + expect(x.a.c == 3) catch @panic("test failure: zig_big_union c"); + expect(x.a.d == 4) catch @panic("test failure: zig_big_union d"); + expect(x.a.e == 5) catch @panic("test failure: zig_big_union e"); } const MedStructMixed = extern struct { @@ -230,6 +247,65 @@ export fn zig_small_struct_ints(x: SmallStructInts) void { expect(x.d == 4) catch @panic("test failure"); } +const SmallPackedStruct = packed struct { + a: u2, + b: u2, + c: u2, + d: u2, + e: bool, +}; +const c_small_packed_struct: fn (SmallPackedStruct) callconv(.C) void = @compileError("TODO: #1481"); +extern fn c_ret_small_packed_struct() SmallPackedStruct; + +// waiting on #1481 +//export fn zig_small_packed_struct(x: SmallPackedStruct) void { +// expect(x.a == 0) catch @panic("test failure"); +// expect(x.b == 1) catch @panic("test failure"); +// expect(x.c == 2) catch @panic("test failure"); +// expect(x.d == 3) catch @panic("test failure"); +// expect(x.e) catch @panic("test failure"); +//} + +test "C ABI small packed struct" { + var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3, .e = true }; + _ = s; //c_small_packed_struct(s); // waiting on #1481 + var s2 = c_ret_small_packed_struct(); + try expect(s2.a == 0); + try expect(s2.b == 1); + try expect(s2.c == 2); + try expect(s2.d == 3); + try expect(s2.e); +} + +const BigPackedStruct = packed struct { + a: u64, + b: u64, + c: u64, + d: u64, + e: u8, +}; +extern fn c_big_packed_struct(BigPackedStruct) void; +extern fn c_ret_big_packed_struct() BigPackedStruct; + +export fn zig_big_packed_struct(x: BigPackedStruct) void { + expect(x.a == 1) catch @panic("test failure"); + expect(x.b == 2) catch @panic("test failure"); + expect(x.c == 3) catch @panic("test failure"); + expect(x.d == 4) catch @panic("test failure"); + expect(x.e == 5) catch @panic("test failure"); +} + +test "C ABI big packed struct" { + var s = BigPackedStruct{ .a = 1, .b = 2, .c = 3, .d = 4, .e = 5 }; + c_big_packed_struct(s); + var s2 = c_ret_big_packed_struct(); + try expect(s2.a == 1); + try expect(s2.b == 2); + try expect(s2.c == 3); + try expect(s2.d == 4); + try expect(s2.e == 5); +} + const SplitStructInt = extern struct { a: u64, b: u8, diff --git a/zig/test/stage2/aarch64.zig b/zig/test/stage2/aarch64.zig index db4539eca9..64e6f95a84 100644 --- a/zig/test/stage2/aarch64.zig +++ b/zig/test/stage2/aarch64.zig @@ -121,8 +121,8 @@ pub fn addCases(ctx: *TestContext) !void { // Regular old hello world case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; - \\extern fn exit(usize) noreturn; + \\extern "c" fn write(usize, usize, usize) usize; + \\extern "c" fn exit(usize) noreturn; \\ \\pub export fn main() noreturn { \\ print(); @@ -141,7 +141,7 @@ pub fn addCases(ctx: *TestContext) !void { // Now using start.zig without an explicit extern exit fn case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ print(); @@ -158,7 +158,7 @@ pub fn addCases(ctx: *TestContext) !void { // Print it 4 times and force growth and realloc. case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ print(); @@ -182,7 +182,7 @@ pub fn addCases(ctx: *TestContext) !void { // Print it once, and change the message. case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ print(); @@ -199,7 +199,7 @@ pub fn addCases(ctx: *TestContext) !void { // Now we print it twice. case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ print(); diff --git a/zig/test/stage2/x86_64.zig b/zig/test/stage2/x86_64.zig index 2725767e95..20bf2264bf 100644 --- a/zig/test/stage2/x86_64.zig +++ b/zig/test/stage2/x86_64.zig @@ -328,7 +328,7 @@ pub fn addCases(ctx: *TestContext) !void { .macos => { // While loops case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ var i: u32 = 0; @@ -349,7 +349,7 @@ pub fn addCases(ctx: *TestContext) !void { // inline while requires the condition to be comptime known. case.addError( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ var i: u32 = 0; @@ -652,7 +652,7 @@ pub fn addCases(ctx: *TestContext) !void { .macos => { // Basic for loop case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ for ("hello") |_| print(); @@ -736,7 +736,7 @@ pub fn addCases(ctx: *TestContext) !void { }), .macos => try case.files.append(.{ .src = - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn print() void { \\ _ = write(1, @ptrToInt("Hello, World!\n"), 14); @@ -814,7 +814,7 @@ pub fn addCases(ctx: *TestContext) !void { }), .macos => try case.files.append(.{ .src = - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\fn print() void { \\ _ = write(1, @ptrToInt("Hello, World!\n"), 14); \\} @@ -1478,7 +1478,7 @@ pub fn addCases(ctx: *TestContext) !void { \\} , "HelloHello, World!\n"), .macos => case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ comptime var len: u32 = 5; @@ -1550,7 +1550,7 @@ pub fn addCases(ctx: *TestContext) !void { \\} , "HeHelHellHello"), .macos => case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ comptime var i: u64 = 2; @@ -1877,8 +1877,8 @@ fn addMacOsTestCases(ctx: *TestContext) !void { // Regular old hello world case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; - \\extern fn exit(usize) noreturn; + \\extern "c" fn write(usize, usize, usize) usize; + \\extern "c" fn exit(usize) noreturn; \\ \\pub export fn main() noreturn { \\ print(); @@ -1897,7 +1897,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void { // Now using start.zig without an explicit extern exit fn case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ print(); @@ -1914,7 +1914,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void { // Print it 4 times and force growth and realloc. case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ print(); @@ -1938,7 +1938,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void { // Print it once, and change the message. case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ print(); @@ -1955,7 +1955,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void { // Now we print it twice. case.addCompareOutput( - \\extern fn write(usize, usize, usize) usize; + \\extern "c" fn write(usize, usize, usize) usize; \\ \\pub fn main() void { \\ print(); diff --git a/zig/test/standalone/c_compiler/test.cpp b/zig/test/standalone/c_compiler/test.cpp index f10a9e0c00..8c533d02cc 100644 --- a/zig/test/standalone/c_compiler/test.cpp +++ b/zig/test/standalone/c_compiler/test.cpp @@ -12,15 +12,22 @@ class CTest { int m_val; }; + +volatile int runtime_val = 456; +CTest global(runtime_val); // test if global initializers are called. + int main (int argc, char *argv[]) { + assert(global.getVal() == 456); + auto* t = new CTest(123); assert(t->getVal()!=456); - if (argc>1) t->printVal(); + + if (argc>1) t->printVal(); bool ok = t->getVal() == 123; delete t; - if (!ok) abort(); + if (!ok) abort(); return 0; } diff --git a/zig/test/translate_c.zig b/zig/test/translate_c.zig index 50072d8085..bd83f8034b 100644 --- a/zig/test/translate_c.zig +++ b/zig/test/translate_c.zig @@ -814,7 +814,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub const Foo = anyopaque; , - \\pub extern fn fun(a: ?*Foo) Foo; + \\pub extern fn fun(a: ?*Foo) void; }); cases.add("duplicate typedef", @@ -1135,11 +1135,31 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define bar 16.e-2l \\#define FOO 0.12345 \\#define BAR .12345 + \\#define baz 1e1 + \\#define BAZ 42e-3f + \\#define foobar -73.L , &[_][]const u8{ "pub const foo = @as(f32, 3.14);", "pub const bar = @as(c_longdouble, 16.0e-2);", "pub const FOO = 0.12345;", "pub const BAR = 0.12345;", + "pub const baz = 1e1;", + "pub const BAZ = @as(f32, 42e-3);", + "pub const foobar = -@as(c_longdouble, 73.0);", + }); + + cases.add("macro defines hexadecimal float", + \\#define FOO 0xf7p38 + \\#define BAR -0X8F.BP5F + \\#define FOOBAR 0X0P+0 + \\#define BAZ -0x.0a5dp+12 + \\#define FOOBAZ 0xfE.P-1l + , &[_][]const u8{ + "pub const FOO = 0xf7p38;", + "pub const BAR = -@as(f32, 0x8F.BP5);", + "pub const FOOBAR = 0x0P+0;", + "pub const BAZ = -0x0.0a5dp+12;", + "pub const FOOBAZ = @as(c_longdouble, 0xfE.0P-1);", }); cases.add("comments", diff --git a/zig/tools/update-linux-headers.zig b/zig/tools/update-linux-headers.zig index 0a3fb85f71..48fdfbbb34 100644 --- a/zig/tools/update-linux-headers.zig +++ b/zig/tools/update-linux-headers.zig @@ -55,7 +55,7 @@ const linux_targets = [_]LibCTarget{ }, LibCTarget{ .name = "arm64", - .arch = .arm64, + .arch = .{ .specific = .aarch64 }, }, LibCTarget{ .name = "csky", diff --git a/zig/tools/update_clang_options.zig b/zig/tools/update_clang_options.zig index 7360f96560..bada964c91 100644 --- a/zig/tools/update_clang_options.zig +++ b/zig/tools/update_clang_options.zig @@ -412,6 +412,18 @@ const known_options = [_]KnownOpt{ .name = "emit-llvm", .ident = "emit_llvm", }, + .{ + .name = "sysroot", + .ident = "sysroot", + }, + .{ + .name = "entry", + .ident = "entry", + }, + .{ + .name = "e", + .ident = "entry", + }, }; const blacklisted_options = [_][]const u8{};