pax_global_header00006660000000000000000000000064142336140740014516gustar00rootroot0000000000000052 comment=191593856663eb126511604f21b8196385c2e385 mescc-tools-Release_1.4.0/000077500000000000000000000000001423361407400154105ustar00rootroot00000000000000mescc-tools-Release_1.4.0/.gitignore000066400000000000000000000022121423361407400173750ustar00rootroot00000000000000## Copyright (C) 2017 Jeremiah Orians ## This file is part of mescc-tools. ## ## mescc-tools is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## mescc-tools 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 General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with mescc-tools. If not, see . # Ignore build directory bin/ # Ignore Temp directory temp/ # Ignore test result directory test/results/ # Ignore temp and special files *.tst *.qst # Ignore bootstrap build files M1-macro-footer.M1 M1-macro.M1 M1-macro.hex2 blood-elf-footer.M1 blood-elf.M1 blood-elf.hex2 hex2_linker-footer.M1 hex2_linker.M1 hex2_linker.hex2 get_machine-footer.M1 get_machine.M1 get_machine.hex2 exec_enable-footer.M1 exec_enable.M1 exec_enable.hex2 mescc-tools-Release_1.4.0/.gitmodules000066400000000000000000000001211423361407400175570ustar00rootroot00000000000000[submodule "M2libc"] path = M2libc url = https://github.com/oriansj/M2libc.git mescc-tools-Release_1.4.0/CHANGELOG.org000066400000000000000000000346661423361407400174270ustar00rootroot00000000000000## Copyright (C) 2017 Jeremiah Orians ## This file is part of mescc-tools ## ## mescc-tools is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## mescc-tools 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 General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with mescc-tools. If not, see . * Current ** Added Added exec support to kaem Added if/else conditionals to kaem Add support for aliases in kaem Added --hex2 and --endian flags to get_machine Kaem now returns more specific messages based on waitpid's status Kaem added --show-exit-codes flag to enable seeing exit codes for subprocesses ** Changed Kaem now places space between echo tokens Kaem now also terminates commands with ; Kaem now is strict by default and you need to pass --non-strict to revert to old behavior ** Fixed Various typos Fix extracting exit status of completed programs in kaem Catch get_machine's --override segfault ** Removed Remove unused getopt include from blood-elf * 1.3 - 2021-10-03 ** Added Hex2 support for RISC-V M1 support for RISC-V Blood-elf support for RISC-V ** Changed clean up $@ behavior for kaem *MAJOR BREAKING CHANGE* make Blood-elf require --little-endian or --big-endian flag to be used (commit db4a332418e7fe5033b2836c9f355f076df325df) ** Fixed Make changing PATH within a kaem script actually change the PATH Multiple typos in hex2 and M1 Correct e_entry behavior for elf example headers Make kaem behave correctly when given a NULL envp Make kaem behave correctly when given an empty envp ** Removed Removed High level prototypes for hex1, hex2 and M0 * 1.2 - 2021-06-09 ** Added netBSD support for tests FreeBSD support for test FreeBSD support for generated binaries Implemented Hash table to speed up M1 Add aligned addressing for AArch64 Produce meaningful warning message when users are not generating ROM images Produce warning for potentially wrong endianess Use hash table for hex2 jump table Add proper escaping support to kaem Adding baseline support for ppc64le in hex2 Add ppc64le support to M1 Add minimal PPC64LE test for M1+hex2 Add RISC-V support to hex2_linker Add RISC-V support to M1 Add --blood flag to get_machine to simplify the process of getting blood-elf flags during bootstrap Added variable expansion collapse support ** Changed Inherrit CFLAGS in kaem makefile Changed M1 to leverage O(1) macro application Pulled all variable initialization outside of loops to fix M2-Planet compatibility Broke kaem tests into individual commands Close files that were fopen'ed Harmonize get_machine flags to support --os and depreciate --OS Replace file_print with more C standard compliant fputs Harmonized on ELF header numbers for architecture numbering ** Fixed Fixed makefiles so guix is able to build Fixed kaem 32bit regression. Spelling mistakes GCC 10 Compatibility issue Behavior of kaem --strict in regards to blank lines Missing makefile dependencies on get_machine catm stopped reading past the end of argv Added missing test and made add_envar update Fix kaem overwriting environment variables Make kaem test14 not locale specific Fixed build failure caused by export LANGUAGE=nl_BE:nl Disable attempting to run Linux binaries on non-Linux hosts Make overly long atoms have a useful error message ** Removed Remove kaem.run in Kaem/ Finish eliminating all functions outside of M2libc * 1.0 - 2020-05-01 ** Added Added builtin cd into kaem Added builtin set into kaem Added builtin pwd into kaem Added working variable substitution into kaem Added kaem subtests Seperate kaem makefile Added fuzzing argument to kaem to prevent damage during fuzzing ** Changed Prevent buffer overflows in kaem Made hex2 argument names more standard Made M1 argument names more standard Moved kaem and its tests into a seperate directory ** Fixed kaem behavior in regards to failing execve kaem segfaults from messy inputs caught Multiple segfaults found from fuzzing Fixed kaem truncation bug Got kaem to run properly on armv7l ** Removed * 0.7 - 2020-01-30 ** Added Added support for AMD64 dwarf footers in blood-elf via --64 Added hex0 for i386 in NASM, M1 and hex0 Added hex1 for i386 in NASM, M1, hex1 and hex0 Added first generation AARCH64 elf header Added hex2 for i386 in NASM, M1, hex2 and hex1 Added M0 for i386 in NASM, M1 and hex2 Added catm for i386 in NASM, M1 and hex0 Added support for EOF in line comments in hex2 and M1; thanks to markjenkins Added prototype M1 Manpage Added prototype hex2 Manpage Added prototype blood-elf Manpage Added prototype kaem Manpage Added prototype get_machine Manpage Added cc_x86 for AMD64 in NASM and M1 Added cc_x86 for x86 in NASM and M1 Added cc_amd64 for AMD64 in NASM and M1 Added cc_amd64 for x86 in NASM and M1 ** Changed ** Fixed Removed duplicate in kaem's help Fixed regression in M1 in regards to knight null padding Removed a series of segfaults ** Removed * 0.6 - 2019-04-14 ** Added Added template ELF headers for ARM Added initial support for ARM Added official hex0 seed for AMD64 Added official hex1 seed for AMD64 Added support for Added catm NASM prototype to simplify build Added catm M1 prototype to reduce bootstrap dependency Added catm hex0 prototype to eliminate bootstrap dependencies down to hex0 Added M0 NASM prototype to simplify build Added M0 M1 prototype to reduce bootstrap dependency Added M0 hex2 prototype to eliminate bootstrap dependencies down to hex2 Verified ARM port to support M2-Planet ** Changed Updated build.sh and kaem.run to the current mescc-tools syntax Reduced get_machine's build dependencies Cleaned up x86 elf headers Removed kaem's dependence on getopt Replaced --Architecture with --architecture changed get_machine's default output to filter machine names into known families Reduced M1 null padding of strings to a single null for all architectures except Knight Updated AMD64 bootstrap kaem.run to include steps from hex0 to M0 ** Fixed Fixed broken test9 thanks to janneke Fixed wrong displacement calculations for ARM immediates Fixed typo in license header Fixed kaem.run to actually function and produce identical results Fixed regression caused by linux 4.17 Removed false newline added in numerate_number for zero case Fixed broken bootstrap script ** Removed Removed final dependency on getopt Removed need to know architecture numbers as that was a bad idea * 0.5 - 2018-06-15 ** Added Added INSTALL notes Added HACKING notes Added examples of minimal Hex1, Hex2 and M1-macro programs that may need to be written to bootstrap a particular architecture. Added useful functions to reduce bootstrap dependencies Added support for binary output in M1-macro ** Changed Changed Knight architecture offset calculation to match new standard Updated test3 lisp.s to include more functionality Updated test3 definitions file to reflect changes in Knight instruction encoding enhanced README to be more useful Pulled numerate_string functionality out of hex2 and M1 into a shared library Eliminated getopt from M1-Macro, hex2-linker and blood-elf; use --Architecture 1 instead of --Architecture=1 ** Fixed Corrected M1-macro incorrectly expressing negative numbers Updated test3 checksum to reflect new version of lisp.s fixed check.sh to actually perform all checks. Fixed build.sh to function in a self-hosting fashion ** Removed Removed blood-elf's dependency on getopt Removed C preprocessor macro from blood-elf needed for mescc support Removed hex2's dependency on getopt Removed C preprocessor macro from hex2 needed for mescc support Removed need for octal support in the building of hex2 Removed M1's dependency on getopt Removed C preprocessor macro from M1 needed for mescc support Removed need for sprintf from M1 * 0.4 - 2018-02-24 ** Added Added file checks to reduce the number of error messageless faults Added a current generation M1.M1 file as a test for mescc-tools Added prototype kaem build script M1-macro now catches undefined macros to allow easier troubleshooting Added kaem build tool Added ability to track build progress in kaem Added support for line escapes in kaem Added support for --strict in kaem to halt in the event of errors Added selectable script file support in kaem Added support for PATH search to kaem with fallbacks in the event of NULL environments ** Changed flipped blood-elf from ignoring :: to :_ converted test8 into a full test Added bash style line comments to kaem Added support for raw strings to kaem Stopped showing comment lines in kaem --verbose Removed dependence on getenv to have more control over environmental lookup ** Fixed Fixed stack overflow bug caused by too deeply nested recursion by transforming into iteration Fixed default repo to point to current repo Added missing license header to kaem.c Fixed infinite looping in kaem scripts that hit an error that resets the file descriptor ** Removed Removed need for strtol Removed need for a global variable in M1-Macro Removed legacy functions from kaem * 0.3 - 2017-12-01 ** Added Incorporated a hex0 test which implements hex1 functionality Added --output and --exec_enable options to hex2 Added --output option to M1 Wrote Hex1 in Hex0 for AMD64/ELF Added the ability to specify an output file Added exec_enable to allow the arbitrary setting of executable bits Added get_machine to enable better scripting Incorporated janneke's build scripts Added a test to test for unusual nybble and byte order/formatting issues Added blood-elf to generate elf footer capable of being used by objdump ** Changed Renamed MESCC_Tools to mescc-tools to harmonize with guix package name Now all tests will be architecture specific Modified sprintf to behave correctly for negative numbers Converted blood-elf to read M1-macro input and output M1-macro output replaced uint with unsigned to better match the standard Harmonized MAXSTRING to 4096bytess ** Fixed Incorporated janneke's patchs to fix mescc compatibility Fixed test on ARM platforms Fixed range check to behave correctly with unsigned ints ** Removed Removed the need to redirect hex2 output into a file Removed the need for chmod u+x in development paths Removed the need to redirect M1 output into a file Removed the need for chmod entirely from bootstrap path Removed dependency on shell supporting redirects Removed need for stdint and stdbool Removed need for enum support Removed need for strtol in M1-macro * 0.2 - 2017-07-25 ** Added created test2 (a 32bit x86 hex assembler) with its associated build and test changes Fixed proof answers for test1 and test2 Added support to M0 for multiple architectures Added range checking into M0 to make sure immediates will fit into specified space Added a basic tutorial for generating new M0 definitions Created a M1 compatible version of test0 Added an amd64 program for enabling execute bits (might need to later alter the 0777) Added an i386 program for enabling execute bits (might need to later alter the 0777) Added rain1's improvements to gcc flags Added rain1's stack reduction recommendations Incorporated an AMD64/elf hex1 example program as a test Incorporated Test7 into make test and make clean flows ** Changed Adjusted tags to reflect current CHANGELOG Make test now depends upon test2 completing Changed how M0 processes input to reduce stack usage and improve performance Renamed M0 to M1 to reflect the additional functionality it provides Applied Janneke's patch for accepting hex numerics in M1 Refactored x86/amd64 elf headers to a standard to avoid duplication Standardized C flags for compiling M1 and Hex2 Made eval_immediates iterative instead of recursive Made identify_macros iterative instead of recursive Made process_string iterative instead of recursive Made preserve_other iterative instead of recursive Made print_hex iterative instead of recursive Incremented version numbers for hex2 and M1 Updated guix.scm to match the new version and finish the release Converted guix.scm definition for mescc_tools to use uri method instead of git ** Fixed Removed unrequired temp file in test1 Clarified meaning of Label>base displacement conditional Corrected error in test0 elf32 Test1 and Test2 to reflect the fact that /bin/bash doesn't exist in guix Fixed M0 regression to continue to support original test code Corrected makefile and build scripts to reflect rename Modified test make scripts to reflect new standard elf headers Fixed base address needed by test5 and its associated checksum Harmonized flags for displaying version with standard ** Removed Removed bashisms from Test1 and Test2 to allow proper behavior on debian based systems Removed alerting on missing files in cleanup target Removed massive M0 Definition lists as they don't serve a useful purpose * 0.1 - 2017-06-25 ** Added Incorporated support for little Endian output format in hex2 Incorporated support for multiple input files in hex2 Added range checking for Hex2 Added support for 1 and 4 byte relative displacements Added Hex2 Test Added the ability to specify a new base address Added example M0 x86 opcode definitions Incorporated support for multiple input files in M0 Added support for little Endian immediate output in M0 Added Hex assembler example test Added support for Label>base in Hex2 Added Version info Added install target Added inital guix package definition ** Changed Displacement calculations are now based on architecture specific rules M0 Immediates now need prefixes to specify the storage space to use for the immediate ** Fixed Behavior regarding !label displacements ** Removed * 0.0 - 2017-05-10 Initial release of MESCC Tools from stage0 High Level prototypes mescc-tools-Release_1.4.0/COPYING000066400000000000000000001045131423361407400164470ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . mescc-tools-Release_1.4.0/Generating_M0_Definitions.org000066400000000000000000000255261423361407400231050ustar00rootroot00000000000000* License ## Copyright (C) 2017 Jeremiah Orians ## This file is part of mescc-tools. ## ## mescc-tools is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## mescc-tools 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 General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with mescc-tools. If not, see . * How to use software to generated opcode information Lets start with a simple program you wish to convert to M1, so to start we are going to write a hex disassembler that uses a lookup table ** simple assembly example .text # section declaration output: .byte 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x0A # we must export the entry point to the ELF linker or loader. # They convientionally recognize _start as their entry point. # Use ld -e main to override the default if you wish .global _start print_byte: # Write what ever is in eax mov $1, %edx # set the size of chars we want mov %eax, %ecx # What we are writing mov $1, %ebx # Stdout File Descriptor mov $4, %eax # the syscall number for write int $0x80 # call the Kernel ret read_byte: # Attempt to read a single byte from STDIN mov $1, %edx # set the size of chars we want mov $input, %ecx # Where to put it mov $0, %ebx # Where are we reading from mov $3, %eax # the syscall number for read int $0x80 # call the Kernel # If we didn't read any bytes jump to Done test %eax, %eax # check what we got jz Done # Got EOF call it done # Move our byte into registers for processing movb input, %al # load char movzx %al, %eax # move char into eax ret _start: loop: call read_byte mov %eax, %esi # We have to zero extend it to use it mov %eax, %ebp # We have to zero extend it to use it # Break out the nibbles shr $4, %esi # Purge the bottom 4 bits and $0xF, %ebp # Chop off all but the bottom 4 bits # add our base pointer add $output, %esi # Use that as our index into our array add $output, %ebp # Use that as our index into our array # Print our first Hex mov %esi, %eax # What we are writing call print_byte # Print our second Hex mov %ebp, %eax # What we are writing call print_byte jmp loop Done: # program completed Successfully mov $0, %ebx # All is well mov $1, %eax # put the exit syscall number in eax int $0x80 # Call it a good day .data write_size = 2 input: .byte write_size ** Build it To build the above program (assuming you put it in a file named foo.S and wish to produce a program called foo): as -o foo.o foo.S ld -o foo foo.S ** objdump its secrets If one were to run: objdump -d foo > opcodes.note *** Which would contain Disassembly of section .text: 08048074 : 8048074: 30 31 xor %dh,(%ecx) 8048076: 32 33 xor (%ebx),%dh 8048078: 34 35 xor $0x35,%al 804807a: 36 37 ss aaa 804807c: 38 39 cmp %bh,(%ecx) 804807e: 41 inc %ecx 804807f: 42 inc %edx 8048080: 43 inc %ebx 8048081: 44 inc %esp 8048082: 45 inc %ebp 8048083: 46 inc %esi 8048084: 0a .byte 0xa 08048085 : 8048085: ba 01 00 00 00 mov $0x1,%edx 804808a: 89 c1 mov %eax,%ecx 804808c: bb 01 00 00 00 mov $0x1,%ebx 8048091: b8 04 00 00 00 mov $0x4,%eax 8048096: cd 80 int $0x80 8048098: c3 ret 08048099 : 8048099: ba 01 00 00 00 mov $0x1,%edx 804809e: b9 f3 90 04 08 mov $0x80490f3,%ecx 80480a3: bb 00 00 00 00 mov $0x0,%ebx 80480a8: b8 03 00 00 00 mov $0x3,%eax 80480ad: cd 80 int $0x80 80480af: 85 c0 test %eax,%eax 80480b1: 74 34 je 80480e7 80480b3: a0 f3 90 04 08 mov 0x80490f3,%al 80480b8: 0f b6 c0 movzbl %al,%eax 80480bb: c3 ret 080480bc <_start>: 80480bc: e8 d8 ff ff ff call 8048099 80480c1: 89 c6 mov %eax,%esi 80480c3: 89 c5 mov %eax,%ebp 80480c5: c1 ee 04 shr $0x4,%esi 80480c8: 83 e5 0f and $0xf,%ebp 80480cb: 81 c6 74 80 04 08 add $0x8048074,%esi 80480d1: 81 c5 74 80 04 08 add $0x8048074,%ebp 80480d7: 89 f0 mov %esi,%eax 80480d9: e8 a7 ff ff ff call 8048085 80480de: 89 e8 mov %ebp,%eax 80480e0: e8 a0 ff ff ff call 8048085 80480e5: eb d5 jmp 80480bc <_start> 080480e7 : 80480e7: bb 00 00 00 00 mov $0x0,%ebx 80480ec: b8 01 00 00 00 mov $0x1,%eax 80480f1: cd 80 int $0x80 ** making sense of the objdump information *** Labels When you see 08048074 : It indicates that at address 0x08048074 the definition of the function output resides. *** 1OP Instructions When you see 8048098: c3 ret It indicates that at address 0x8048098 there is a Return instruction which as the Hex opcode encoding of C3 and could be implemented in M1 as: DEFINE RETURN C3 Or any other mnemonic term that is more optimal for the problem at hand. *** 2OP Instructions When you see 80480c1: 89 c6 mov %eax,%esi It indicate that at address 0x80480C1 there is a Move instruction that copies the value of register eax to register esi and has the Hex opcode encoding of 89C6 and therefor can be defined in M1 as: DEFINE COPY_EAX_To_ESI 89C6 or If we assume (eax=>R0, ebx=>R1, ecx=>R2, edx=>R3, esi=>R4, edi=>R5, ebp=>R6, and esp=>R7) DEFINE COPY_R0_To_R4 89C6 *** Instructions with Immediates or displacements Immediates occur in variable sizes but an immediate can not exist without an instruction **** Trivial example Most immediates are common values such as 1 (01) or -1 (FF..FF) that are immediately obvious: 80480a8: b8 03 00 00 00 mov $0x3,%eax 8048091: b8 04 00 00 00 mov $0x4,%eax 80480ec: b8 01 00 00 00 mov $0x1,%eax Espcially when there is a very familiar pattern and leading (or in x86's case trailing zeros) It should be immediately obvious that B8 is the opcode for loading a 32bit immediate value into eax, which can be written in M1 as: DEFINE MOV_Immediate32_EAX B8 or DEFINE LOADI32_R0 B8 You only need to remember to follow that mnemonic with a 32bit immediate (%4 works) **** Easy example For some immediate instructions the size and placement of the immediate is obvious (or perhaps obvious once you realize the Endianness of the instruction set you are working with) For example: 80480b3: a0 f3 90 04 08 mov 0x80490f3,%al Knowing that x86 is little endian, the 08 should pop out at you. f3 90 04 08 is the little endian encoding of the number 0x080490F3 and thus we know that the opcode is A0 and it requires a 32bit value (An absolute address) and that it writes that result to al (which is the bottom 8bits of the eax register) Thus we can express this opcode as: DEFINE MOV_Absolute32_al A0 or LOAD8_R0_Absolute32 A0 Which then always has to be followed by a 32bit absolute address ($foo works) **** Annoying example For some instructions, you may have to lookup the opcode to determine its length and thus the length of its immediate such as: 80480b1: 74 34 je 80480e7 Which when confronted with such a case, simply lookup the 74 in http://ref.x86asm.net/coder32.html thus resolving to it is both jz and je and it takes a 8bit relative address (the 34). Thus we can define our newly determined opcode in M1 as: DEFINE JE8 74 DEFINE JZ8 74 or DEFINE Jump_if_Zero8 74 but we need to make sure that whenever we use our mnemonic we follow it with a 8bit relative value (!label works well) *** Things objdump gets wrong The thing all disassemblers tend to get wrong and dependes entirely on heuristics is the identification of strings and byte constants. In our case, it has identified our table as a set of instructions (also correctly determined their representation) 08048074 : 8048074: 30 31 xor %dh,(%ecx) 8048076: 32 33 xor (%ebx),%dh 8048078: 34 35 xor $0x35,%al 804807a: 36 37 ss aaa 804807c: 38 39 cmp %bh,(%ecx) 804807e: 41 inc %ecx 804807f: 42 inc %edx 8048080: 43 inc %ebx 8048081: 44 inc %esp 8048082: 45 inc %ebp 8048083: 46 inc %esi 8048084: 0a .byte 0xa In M1 we have the ability to do things like strings to store such a table. Which would probably be the following: :output "0123456789ABCDEF" Which certainly alot easier to read and understand than output: .byte 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x0A * Using that opcode information to write a M1 program Thus we would come to a defintion list that looks something like this: DEFINE MOVZBL_al_To_eax 0FB6C0 DEFINE JE8 74 DEFINE ADD_Immediate32_To_ebp 81C5 DEFINE ADD_Immediate32_To_esi 81C6 DEFINE ANDI8_ebp 83E5 DEFINE TEST_eax_eax 85C0 DEFINE MOV_eax_To_ecx 89C1 DEFINE MOV_eax_To_ebp 89C5 DEFINE MOV_eax_To_esi 89C6 DEFINE MOV_ebp_To_eax 89E8 DEFINE MOV_esi_To_eax 89F0 DEFINE LOAD8_al A0 DEFINE LOADI32_eax B8 DEFINE LOADI32_ecx B9 DEFINE LOADI32_edx BA DEFINE LOADI32_ebx BB DEFINE SHIFT_RIGHT_Immediate8_esi C1EE DEFINE RETURN C3 DEFINE INT_80 CD80 DEFINE CALLI32 E8 DEFINE JUMP8 EB ** emacs tips Using the objdump output, first clear the labels and not instruction data. Then leverage C-x ( and C-x ) to define a keyboard macro that deletes the address from the start of the line. C-x e followed by e repeatedly to clear all of the lines. M-x sort-lines, will sort all selected lines (very useful as now all instructions with the same opcode are next to each other for easy pruning) M-x delete-duplicate-lines will purge all exact duplicates (very handy for compiler output) Then all that remains is determining the immediates and figuring out what line actually does. This is left as an exercise for the reader. mescc-tools-Release_1.4.0/HACKING000066400000000000000000000053101423361407400163760ustar00rootroot00000000000000-*-mode:org-*- ## Copyright (C) 2017 Jeremiah Orians ## This file is part of mescc-tools. ## ## mescc-tools is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## mescc-tools 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 General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with mescc-tools. If not, see . mescc-tools being based on the goal of absolute minimal platform bootstrap. If your hardware doesn't have some crazy engineering decisions, mescc-tools can and likely will be trivially ported to it. * SETUP The most obvious way to setup for mescc-tools development is to install any C compiler and make clone of your choice. * BUILD The standard C based approach to building mescc-tools is simply running: make Should you wish to verify that mescc-tools was built correctly run: make test * ADDING an ARCHITECTURE The process is simple: 1) add an architecture flag for your architecture to hex2_linker.c 2) Then make sure byte and then bit order are correct 3) Tweak to make sure immediate prefixes are the correct size for your architecture 4) Then make sure relative displacements are calculated correctly 5) Then make sure absolute displacements are calculated correctly 6) add an architecture flag for your architecture to M1-Macro.c 7) Then make sure byte and then bit order are correct 8) Tweak to make sure immediate prefixes are the correct size for your architecture 9) If you require unusual string padding, please add that now 10) Write your architecture.def or architecture.M1 file to include instruction and register encodings that map to the required encoding. * ROADMAP The current outstanding work for mescc-tools is several architecture specific bootstrap ports, that unfortunately share C level code but require significant manual labor to implement. * DEBUG The default build process will generate debuggable binaries. as blood-elf will generate the segments and text section required for proper debugging * Bugs mescc-tools is the most unforgiving assembly development environment possible. Things such as manual padding requirements, arbitrary instruction encoding and other features of these tools, make for rapid bootstrapping but horrific development environments. Please only use these tools to bootstrap your system from zero; otherwise cross- compile with gcc and save yourself the pain. mescc-tools-Release_1.4.0/INSTALL000066400000000000000000000022141423361407400164400ustar00rootroot00000000000000## Copyright (C) 2017 Jeremiah Orians ## This file is part of mescc-tools. ## ## mescc-tools is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## mescc-tools 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 General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with mescc-tools. If not, see . Building and Installing mescc-tools * Get it git clone https://github.com/oriansj/mescc-tools.git * Prerequisites ** Bootstrapping mescc-tools can be bootstrapped from a simple hex assembler. mescc-tools-seed contains the steps for several architectures on posix systems to do so. ** Development The tools required for easier development include binutils, gcc and make * Build it make * Check it make test * Install it make install mescc-tools-Release_1.4.0/Kaem/000077500000000000000000000000001423361407400162655ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/.gitignore000066400000000000000000000002301423361407400202500ustar00rootroot00000000000000# Ignore build directory bin/ # Ignore Temp directory temp/ # Ignore test result directory test/results/ # Ignore temp and special files *.tst *.qst mescc-tools-Release_1.4.0/Kaem/README000066400000000000000000000003131423361407400171420ustar00rootroot00000000000000kaem is the world's worst build tool. You really really should use make instead. This tool exists only as the bare bottom floor scriptable build tool for bootstrapping. Avoid as there be dragons here. mescc-tools-Release_1.4.0/Kaem/kaem.c000066400000000000000000000746271423361407400173660ustar00rootroot00000000000000/* Copyright (C) 2016-2020 Jeremiah Orians * Copyright (C) 2020 fosslinux * Copyright (C) 2021 Andrius Štikonas * This file is part of mescc-tools. * * mescc-tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mescc-tools 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mescc-tools. If not, see . */ #include #include #include #include #include #include "kaem.h" /* Prototypes from other files */ void handle_variables(char** argv, struct Token* n); /* * UTILITY FUNCTIONS */ /* Function to find a character in a string */ char* find_char(char* string, char a) { if(0 == string[0]) { return NULL; } while(a != string[0]) { string = string + 1; if(0 == string[0]) { return string; } } return string; } /* Function to find the length of a char**; an array of strings */ int array_length(char** array) { int length = 0; while(array[length] != NULL) { length = length + 1; } return length; } /* Search for a variable in the token linked-list */ char* token_lookup(char* variable, struct Token* token) { /* Start at the head */ struct Token* n = token; /* Loop over the linked-list */ while(n != NULL) { if(match(variable, n->var)) { /* We have found the correct node */ return n->value; /* Done */ } /* Nope, try the next */ n = n->next; } /* We didn't find anything! */ return NULL; } /* Search for a variable in the env linked-list */ char* env_lookup(char* variable) { return token_lookup(variable, env); } /* Search for a variable in the alias linked-list */ char* alias_lookup(char* variable) { return token_lookup(variable, alias); } /* Find the full path to an executable */ char* find_executable(char* name) { if(match("", name)) { return NULL; } if(('.' == name[0]) || ('/' == name[0])) { /* assume names that start with . or / are relative or absolute */ return name; } char* trial = calloc(MAX_STRING, sizeof(char)); char* MPATH = calloc(MAX_STRING, sizeof(char)); /* Modified PATH */ require(MPATH != NULL, "Memory initialization of MPATH in find_executable failed\n"); strcpy(MPATH, PATH); FILE* t; char* next = find_char(MPATH, ':'); int index; int offset; int mpath_length; int name_length; int trial_length; while(NULL != next) { /* Reset trial */ trial_length = strlen(trial); for(index = 0; index < trial_length; index = index + 1) { trial[index] = 0; } next[0] = 0; /* prepend_string(MPATH, prepend_string("/", name)) */ mpath_length = strlen(MPATH); for(index = 0; index < mpath_length; index = index + 1) { require(MAX_STRING > index, "Element of PATH is too long\n"); trial[index] = MPATH[index]; } trial[index] = '/'; offset = strlen(trial); name_length = strlen(name); for(index = 0; index < name_length; index = index + 1) { require(MAX_STRING > index, "Element of PATH is too long\n"); trial[index + offset] = name[index]; } /* Try the trial */ require(strlen(trial) < MAX_STRING, "COMMAND TOO LONG!\nABORTING HARD\n"); t = fopen(trial, "r"); if(NULL != t) { fclose(t); return trial; } MPATH = next + 1; next = find_char(MPATH, ':'); } return NULL; } /* Function to convert a Token linked-list into an array of strings */ char** list_to_array(struct Token* s) { struct Token* n; n = s; char** array = calloc(MAX_ARRAY, sizeof(char*)); require(array != NULL, "Memory initialization of array in conversion of list to array failed\n"); char* element = calloc(MAX_STRING, sizeof(char)); require(element != NULL, "Memory initialization of element in conversion of list to array failed\n"); int index = 0; int i; int value_length; int var_length; int offset; while(n != NULL) { /* Loop through each node and assign it to an array index */ array[index] = calloc(MAX_STRING, sizeof(char)); require(array[index] != NULL, "Memory initialization of array[index] in conversion of list to array failed\n"); /* Bounds checking */ /* No easy way to tell which it is, output generic message */ require(index < MAX_ARRAY, "SCRIPT TOO LONG or TOO MANY ENVARS\nABORTING HARD\n"); if(n->var == NULL) { /* It is a line */ array[index] = n->value; } else { /* It is a var */ /* prepend_string(n->var, prepend_string("=", n->value)) */ var_length = strlen(n->var); for(i = 0; i < var_length; i = i + 1) { element[i] = n->var[i]; } element[i] = '='; i = i + 1; offset = i; value_length = strlen(n->value); for(i = 0; i < value_length; i = i + 1) { element[i + offset] = n->value[i]; } } /* Insert elements if not empty */ if(!match("", element)) { strcpy(array[index], element); } n = n->next; index = index + 1; /* Reset element */ for(i = 0; i < MAX_STRING; i = i + 1) { element[i] = 0; } } return array; } /* Function to handle the correct options for escapes */ int handle_escape(int c) { if(c == '\n') { /* Do nothing - eat up the newline */ return -1; } else if('n' == c) { /* Add a newline to the token */ return '\n'; } else if('r' == c) { /* Add a return to the token */ return '\r'; } else if('\\' == c) { /* Add a real backslash to the token */ return '\\'; } else { /* Just add it to the token (eg, quotes) */ return c; } } /* * TOKEN COLLECTION FUNCTIONS */ /* Function for skipping over line comments */ void collect_comment(FILE* input) { int c; /* Eat up the comment, one character at a time */ /* * Sanity check that the comment ends with \n. * Remove the comment from the FILE* */ do { c = fgetc(input); /* We reached an EOF!! */ require(EOF != c, "IMPROPERLY TERMINATED LINE COMMENT!\nABORTING HARD\n"); } while('\n' != c); /* We can now be sure it ended with \n -- and have purged the comment */ } /* Function for collecting strings and removing the "" pair that goes with them */ int collect_string(FILE* input, char* n, int index) { int string_done = FALSE; int c; do { /* Bounds check */ require(MAX_STRING > index, "LINE IS TOO LONG\nABORTING HARD\n"); c = fgetc(input); require(EOF != c, "IMPROPERLY TERMINATED STRING!\nABORTING HARD\n"); if('\\' == c) { /* We are escaping the next character */ /* This correctly handles escaped quotes as it just returns the quote */ c = fgetc(input); c = handle_escape(c); n[index] = c; index = index + 1; } else if('"' == c) { /* End of string */ string_done = TRUE; } else { n[index] = c; index = index + 1; } } while(string_done == FALSE); return index; } /* Function to parse and assign token->value */ int collect_token(FILE* input, char* n, int last_index) { int c; int cc; int token_done = FALSE; int index = 0; do { /* Loop over each character in the token */ c = fgetc(input); /* Bounds checking */ require(MAX_STRING > index, "LINE IS TOO LONG\nABORTING HARD\n"); if(EOF == c) { /* End of file -- this means script complete */ /* We don't actually exit here. This logically makes more sense; * let the code follow its natural path of execution and exit * sucessfuly at the end of main(). */ token_done = TRUE; command_done = TRUE; return -1; } else if((' ' == c) || ('\t' == c)) { /* Space and tab are token separators */ token_done = TRUE; } else if(('\n' == c) || (';' == c)) { /* Command terminates at the end of a line or at semicolon */ command_done = TRUE; token_done = TRUE; if(0 == index) { index = last_index; } } else if('"' == c) { /* Handle strings -- everything between a pair of "" */ index = collect_string(input, n, index); token_done = TRUE; } else if('#' == c) { /* Handle line comments */ collect_comment(input); command_done = TRUE; token_done = TRUE; if(0 == index) { index = last_index; } } else if('\\' == c) { /* Support for escapes */ c = fgetc(input); /* Skips over \, gets the next char */ cc = handle_escape(c); if(-1 != cc) { /* We need to put it into the token */ n[index] = cc; } index = index + 1; } else if(0 == c) { /* We have come to the end of the token */ token_done = TRUE; } else { /* It's a character to assign */ n[index] = c; index = index + 1; } } while(token_done == FALSE); return index; } /* Function to parse string and assign token->value */ int collect_alias_token(char* input, char* n, int index) { int c; int cc; int token_done = FALSE; int output_index = 0; do { /* Loop over each character in the token */ c = input[index]; index = index + 1; if((' ' == c) || ('\t' == c)) { /* Space and tab are token separators */ token_done = TRUE; } else if('\\' == c) { /* Support for escapes */ c = input[index]; index = index + 1; cc = handle_escape(c); /* We need to put it into the token */ n[output_index] = cc; output_index = output_index + 1; } else if(0 == c) { /* We have come to the end of the token */ token_done = TRUE; index = 0; } else { /* It's a character to assign */ n[output_index] = c; output_index = output_index + 1; } } while(token_done == FALSE); return index; } /* * EXECUTION FUNCTIONS * Note: All of the builtins return SUCCESS (0) when they exit successfully * and FAILURE (1) when they fail. */ /* Function to check if the token is an envar */ int is_envar(char* token) { int i = 0; int token_length = strlen(token); while(i < token_length) { if(token[i] == '=') { return FAILURE; } i = i + 1; } return SUCCESS; } /* Add an envar */ void add_envar() { /* Pointers to strings we want */ char* name = calloc(strlen(token->value) + 4, sizeof(char)); char* value = token->value; char* newvalue; int i = 0; /* Isolate the name */ while('=' != value[i]) { name[i] = value[i]; i = i + 1; } /* Isolate the value */ newvalue = name + i + 2; value = value + i + 1; i = 0; require(0 != value[i], "add_envar received improper variable\n"); while(0 != value[i]) { newvalue[i] = value[i]; i = i + 1; } /* If we are in init-mode and this is the first var env == NULL, rectify */ if(env == NULL) { env = calloc(1, sizeof(struct Token)); require(env != NULL, "Memory initialization of env failed\n"); env->var = name; /* Add our first variable */ } /* * If the name of the envar is PATH, then we need to set our (internal) * global PATH value. */ if(match(name, "PATH")) { strcpy(PATH, newvalue); } struct Token* n = env; /* Find match if possible */ while(!match(name, n->var)) { if(NULL == n->next) { n->next = calloc(1, sizeof(struct Token)); require(n->next != NULL, "Memory initialization of next env node in add_envar failed\n"); n->next->var = name; } /* Loop will match and exit */ n = n->next; } /* Since we found the variable we need only to set it to its new value */ n->value = newvalue; } /* Add an alias */ void add_alias() { token = token->next; /* Skip the actual alias */ if(token->next == NULL) { /* No arguments */ char** array = list_to_array(alias); int index = 0; while(array[index] != NULL) { fputs(array[index], stdout); fputc('\n', stdout); index = index + 1; } fflush(stdout); return; } if(!is_envar(token->value)) { char** array = list_to_array(token); int index = 0; while(array[index] != NULL) { fputs(array[index], stdout); fputc(' ', stdout); index = index + 1; } fputc('\n', stdout); fflush(stdout); return; } /* Pointers to strings we want */ char* name = calloc(strlen(token->value) + 4, sizeof(char)); char* value = token->value; char* newvalue; int i = 0; /* Isolate the name */ while('=' != value[i]) { name[i] = value[i]; i = i + 1; } /* Isolate the value */ newvalue = name + i + 2; value = value + i + 1; i = 0; require(0 != value[i], "add_alias received improper variable\n"); while(0 != value[i]) { newvalue[i] = value[i]; i = i + 1; } /* If this is the first alias, rectify */ if(alias == NULL) { alias = calloc(1, sizeof(struct Token)); require(alias != NULL, "Memory initialization of alias failed\n"); alias->var = name; /* Add our first variable */ } struct Token* n = alias; /* Find match if possible */ while(!match(name, n->var)) { if(NULL == n->next) { n->next = calloc(1, sizeof(struct Token)); require(n->next != NULL, "Memory initialization of next alias node in alias failed\n"); n->next->var = name; } /* Loop will match and exit */ n = n->next; } /* Since we found the variable we need only to set it to its new value */ n->value = newvalue; } /* cd builtin */ int cd() { if(NULL == token->next) { return FAILURE; } token = token->next; if(NULL == token->value) { return FAILURE; } int ret = chdir(token->value); if(0 > ret) { return FAILURE; } return SUCCESS; } /* pwd builtin */ int pwd() { char* path = calloc(MAX_STRING, sizeof(char)); require(path != NULL, "Memory initialization of path in pwd failed\n"); getcwd(path, MAX_STRING); require(!match("", path), "getcwd() failed\n"); fputs(path, stdout); fputs("\n", stdout); return SUCCESS; } /* set builtin */ int set() { /* Get the options */ int i; if(NULL == token->next) { goto cleanup_set; } token = token->next; if(NULL == token->value) { goto cleanup_set; } char* options = calloc(MAX_STRING, sizeof(char)); require(options != NULL, "Memory initialization of options in set failed\n"); int last_position = strlen(token->value) - 1; for(i = 0; i < last_position; i = i + 1) { options[i] = token->value[i + 1]; } /* Parse the options */ int options_length = strlen(options); for(i = 0; i < options_length; i = i + 1) { if(options[i] == 'a') { /* set -a is on by default and cannot be disabled at this time */ if(WARNINGS) { fputs("set -a is on by default and cannot be disabled\n", stdout); } continue; } else if(options[i] == 'e') { /* Fail on failure */ STRICT = TRUE; } else if(options[i] == 'x') { /* Show commands as executed */ /* TODO: this currently behaves like -v. Make it do what it should */ VERBOSE = TRUE; /* * Output the set -x because VERBOSE didn't catch it before. * We don't do just -x because we support multiple options in one command, * eg set -ex. */ fputs(" +> set -", stdout); fputs(options, stdout); fputs("\n", stdout); fflush(stdout); } else { /* Invalid */ fputc(options[i], stderr); fputs(" is an invalid set option!\n", stderr); exit(EXIT_FAILURE); } } return SUCCESS; cleanup_set: return FAILURE; } /* echo builtin */ void echo() { if(token->next == NULL) { /* No arguments */ fputs("\n", stdout); return; } if(token->next->value == NULL) { /* No arguments */ fputs("\n", stdout); return; } token = token->next; /* Skip the actual echo */ while(token != NULL) { /* Output each argument to echo to stdout */ if(token->value == NULL) { break; } fputs(token->value, stdout); if(NULL != token->next) { /* M2-Planet doesn't short circuit */ if(NULL != token->next->value) fputc(' ', stdout); } token = token->next; } fputs("\n", stdout); } /* unset builtin */ void unset() { struct Token* e; /* We support multiple variables on the same line */ struct Token* t; t = token->next; while(t != NULL) { e = env; /* Look for the variable; we operate on ->next because we need to remove ->next */ while(e->next != NULL) { if(NULL == t->value) { break; } if(match(e->next->var, t->value)) { break; } e = e->next; } t = t->next; /* If it's NULL nothing was found */ if(e->next == NULL) { continue; } /* Otherwise there is something to unset */ e->next = e->next->next; } } void execute(FILE* script, char** argv); int _execute(FILE* script, char** argv); int collect_command(FILE* script, char** argv); /* if builtin */ void if_cmd(FILE* script, char** argv) { int index; int old_VERBOSE; token = token->next; /* Skip the actual if */ /* Do not check for successful exit status */ int if_status = _execute(script, argv); old_VERBOSE = VERBOSE; VERBOSE = VERBOSE && !if_status; do { index = collect_command(script, argv); require(index != -1, "Unexpected EOF, improperly terminated if statement.\n"); if(0 == index) { continue; } if(0 == if_status) { /* Stuff to exec */ execute(script, argv); } if(match(token->value, "else")) { if_status = !if_status; } } while(!match(token->value, "fi")); VERBOSE = old_VERBOSE; } int what_exit(char* program, int status) { /*********************************************************************************** * If the low-order 8 bits of w_status are equal to 0x7F or zero, the child * * process has stopped. If the low-order 8 bits of w_status are non-zero and are * * not equal to 0x7F, the child process terminated due to a signal otherwise, the * * child process terminated due to an exit() call. * * * * In the event it was a signal that stopped the process the top 8 bits of * * w_status contain the signal that caused the process to stop. * * * * In the event it was terminated the bottom 7 bits of w_status contain the * * terminating error number for the process. * * * * If bit 0x80 of w_status is set, a core dump was produced. * ***********************************************************************************/ int WIFEXITED = !(status & 0x7F); int WEXITSTATUS = (status & 0xFF00) >> 8; int WTERMSIG = status & 0x7F; int WCOREDUMP = status & 0x80; int WIFSIGNALED = !((0x7F == WTERMSIG) || (0 == WTERMSIG)); int WIFSTOPPED = ((0x7F == WTERMSIG) && (0 == WCOREDUMP)); if(WIFEXITED) { if(VERBOSE_EXIT) { fputc('\n', stderr); fputs(program, stderr); fputs(" normal termination, exit status = ", stderr); fputs(int2str(WEXITSTATUS, 10, TRUE), stderr); fputs("\n\n\n", stderr); } return WEXITSTATUS; } else if (WIFSIGNALED) { fputc('\n', stderr); fputs(program, stderr); fputs(" abnormal termination, signal number = ", stderr); fputs(int2str(WTERMSIG, 10, TRUE), stderr); fputc('\n', stderr); if(WCOREDUMP) fputs("core dumped\n", stderr); return WTERMSIG; } else if(WIFSTOPPED) { fputc('\n', stderr); fputs(program, stderr); fputs(" child stopped, signal number = ", stderr); fputs(int2str(WEXITSTATUS, 10, TRUE), stderr); fputc('\n', stderr); return WEXITSTATUS; } fputc('\n', stderr); fputs(program, stderr); fputs(" :: something crazy happened with execve\nI'm just gonna get the hell out of here\n", stderr); exit(EXIT_FAILURE); } /* Execute program and check for error */ void execute(FILE* script, char** argv) { int status = _execute(script, argv); if(STRICT == TRUE && (0 != status)) { /* Clearly the script hit an issue that should never have happened */ fputs("Subprocess error ", stderr); fputs(int2str(status, 10, TRUE), stderr); fputs("\nABORTING HARD\n", stderr); exit(EXIT_FAILURE); } } /* Execute program */ int _execute(FILE* script, char** argv) { /* Run the command */ /* rc = return code */ int rc; /* exec without forking */ int exec = FALSE; /* Actually do the execution */ if(is_envar(token->value) == TRUE) { add_envar(); return 0; } else if(match(token->value, "cd")) { rc = cd(); if(STRICT) { require(rc == SUCCESS, "cd failed!\n"); } return 0; } else if(match(token->value, "set")) { rc = set(); if(STRICT) { require(rc == SUCCESS, "set failed!\n"); } return 0; } else if(match(token->value, "alias")) { add_alias(); return 0; } else if(match(token->value, "pwd")) { rc = pwd(); if(STRICT) { require(rc == SUCCESS, "pwd failed!\n"); } return 0; } else if(match(token->value, "echo")) { echo(); return 0; } else if(match(token->value, "unset")) { unset(); return 0; } else if(match(token->value, "exec")) { token = token->next; /* Skip the actual exec */ exec = TRUE; } else if(match(token->value, "if")) { if_cmd(script, argv); return 0; } else if(match(token->value, "then")) { /* ignore */ return 0; } else if(match(token->value, "else")) { /* ignore */ return 0; } else if(match(token->value, "fi")) { /* ignore */ return 0; } /* If it is not a builtin, run it as an executable */ int status; /* i.e. return code */ char** array; char** envp; /* Get the full path to the executable */ char* program = find_executable(token->value); /* Check we can find the executable */ if(NULL == program) { if(STRICT == TRUE) { fputs("WHILE EXECUTING ", stderr); fputs(token->value, stderr); fputs(" NOT FOUND!\nABORTING HARD\n", stderr); exit(EXIT_FAILURE); } /* If we are not strict simply return */ return 0; } int f = 0; if(!exec) { f = fork(); } /* Ensure fork succeeded */ if(f == -1) { fputs("WHILE EXECUTING ", stderr); fputs(token->value, stderr); fputs("fork() FAILED\nABORTING HARD\n", stderr); exit(EXIT_FAILURE); } else if(f == 0) { /* Child */ /************************************************************** * Fuzzing produces random stuff; we don't want it running * * dangerous commands. So we just don't execve. * * But, we still do the list_to_array calls to check for * * segfaults. * **************************************************************/ array = list_to_array(token); envp = list_to_array(env); if(FALSE == FUZZING) { /* We are not fuzzing */ /* execve() returns only on error */ execve(program, array, envp); } /* Prevent infinite loops */ _exit(EXIT_FAILURE); } /* Otherwise we are the parent */ /* And we should wait for it to complete */ waitpid(f, &status, 0); return what_exit(program, status); } int collect_command(FILE* script, char** argv) { command_done = FALSE; /* Initialize token */ struct Token* n; n = calloc(1, sizeof(struct Token)); require(n != NULL, "Memory initialization of token in collect_command failed\n"); char* s = calloc(MAX_STRING, sizeof(char)); require(s != NULL, "Memory initialization of token in collect_command failed\n"); token = n; int index = 0; int alias_index; char* alias_string; /* Get the tokens */ while(command_done == FALSE) { index = collect_token(script, s, index); /* Don't allocate another node if the current one yielded nothing, OR * if we are done. */ if(match(s, "")) { continue; } alias_string = alias_lookup(s); alias_index = 0; do { if(alias_string != NULL) { alias_index = collect_alias_token(alias_string, s, alias_index); } /* add to token */ n->value = s; s = calloc(MAX_STRING, sizeof(char)); require(s != NULL, "Memory initialization of next token node in collect_command failed\n"); /* Deal with variables */ handle_variables(argv, n); /* If the variable expands into nothing */ if(match(n->value, " ")) { n->value = NULL; continue; } /* Prepare for next loop */ n->next = calloc(1, sizeof(struct Token)); require(n->next != NULL, "Memory initialization of next token node in collect_command failed\n"); n = n->next; } while(alias_index != 0); } /* -1 means the script is done */ if(EOF == index) { return index; } /* Output the command if verbose is set */ /* Also if there is nothing in the command skip over */ if(VERBOSE && !match(token->value, "") && !match(token->value, NULL)) { n = token; fputs(" +>", stdout); while(n != NULL) { /* Print out each token token */ fputs(" ", stdout); /* M2-Planet doesn't let us do this in the while */ if(n->value != NULL) { if(!match(n->value, "")) { fputs(n->value, stdout); } } n = n->next; } fputc('\n', stdout); fflush(stdout); } return index; } /* Function for executing our programs with desired arguments */ void run_script(FILE* script, char** argv) { int index; while(TRUE) { /* * Tokens has to be reset each time, as we need a new linked-list for * each line. * See, the program flows like this as a high level overview: * Get line -> Sanitize line and perform variable replacement etc -> * Execute line -> Next. * We don't need the previous lines once they are done with, so tokens * are hence for each line. */ index = collect_command(script, argv); /* -1 means the script is done */ if(EOF == index) { break; } if(0 == index) { continue; } /* Stuff to exec */ execute(script, argv); } } /* Function to populate env */ void populate_env(char** envp) { /* You can't populate a NULL environment */ if(NULL == envp) { return; } /* avoid empty arrays */ int max = array_length(envp); if(0 == max) { return; } /* Initialize env and n */ env = calloc(1, sizeof(struct Token)); require(env != NULL, "Memory initialization of env failed\n"); struct Token* n; n = env; int i; int j; int k; char* envp_line; for(i = 0; i < max; i = i + 1) { n->var = calloc(MAX_STRING, sizeof(char)); require(n->var != NULL, "Memory initialization of n->var in population of env failed\n"); n->value = calloc(MAX_STRING, sizeof(char)); require(n->value != NULL, "Memory initialization of n->var in population of env failed\n"); j = 0; /* * envp is weird. * When referencing envp[i]'s characters directly, they were all jumbled. * So just copy envp[i] to envp_line, and work with that - that seems * to fix it. */ envp_line = calloc(MAX_STRING, sizeof(char)); require(envp_line != NULL, "Memory initialization of envp_line in population of env failed\n"); strcpy(envp_line, envp[i]); while(envp_line[j] != '=') { /* Copy over everything up to = to var */ n->var[j] = envp_line[j]; j = j + 1; } /* If we get strange input, we need to ignore it */ if(n->var == NULL) { continue; } j = j + 1; /* Skip over = */ k = 0; /* As envp[i] will continue as j but n->value begins at 0 */ while(envp_line[j] != 0) { /* Copy everything else to value */ n->value[k] = envp_line[j]; j = j + 1; k = k + 1; } /* Sometimes, we get lines like VAR=, indicating nothing is in the variable */ if(n->value == NULL) { n->value = ""; } /* Advance to next part of linked list */ n->next = calloc(1, sizeof(struct Token)); require(n->next != NULL, "Memory initialization of n->next in population of env failed\n"); n = n->next; } /* Get rid of node on the end */ n = NULL; /* Also destroy the n->next reference */ n = env; while(n->next->var != NULL) { n = n->next; } n->next = NULL; } int main(int argc, char** argv, char** envp) { VERBOSE = FALSE; VERBOSE_EXIT = FALSE; STRICT = TRUE; FUZZING = FALSE; WARNINGS = FALSE; char* filename = "kaem.run"; FILE* script = NULL; /* Initalize structs */ token = calloc(1, sizeof(struct Token)); require(token != NULL, "Memory initialization of token failed\n"); int i = 1; /* Loop over arguments */ while(i <= argc) { if(NULL == argv[i]) { /* Ignore the argument */ i = i + 1; } else if(match(argv[i], "-h") || match(argv[i], "--help")) { /* Help information */ fputs("Usage: ", stdout); fputs(argv[0], stdout); fputs(" [-h | --help] [-V | --version] [--file filename | -f filename] [-i | --init-mode] [-v | --verbose] [--non-strict] [--warn] [--fuzz]\n", stdout); exit(EXIT_SUCCESS); } else if(match(argv[i], "-f") || match(argv[i], "--file")) { /* Set the filename */ if(argv[i + 1] != NULL) { filename = argv[i + 1]; } i = i + 2; } else if(match(argv[i], "-i") || match(argv[i], "--init-mode")) { /* init mode does not populate env */ INIT_MODE = TRUE; i = i + 1; } else if(match(argv[i], "-V") || match(argv[i], "--version")) { /* Output version */ fputs("kaem version 1.4.0\n", stdout); exit(EXIT_SUCCESS); } else if(match(argv[i], "-v") || match(argv[i], "--verbose")) { /* Set verbose */ VERBOSE = TRUE; i = i + 1; } else if(match(argv[i], "--strict")) { /* it is a NOP */ STRICT = TRUE; i = i + 1; } else if(match(argv[i], "--non-strict")) { /* Set strict */ STRICT = FALSE; i = i + 1; } else if(match(argv[i], "--warn")) { /* Set warnings */ WARNINGS = TRUE; i = i + 1; } else if(match(argv[i], "--fuzz")) { /* Set fuzzing */ FUZZING = TRUE; i = i + 1; } else if(match(argv[i], "--show-exit-codes")) { /* show exit codes */ VERBOSE_EXIT = TRUE; i = i + 1; } else if(match(argv[i], "--")) { /* Nothing more after this */ break; } else { /* We don't know this argument */ fputs("UNKNOWN ARGUMENT\n", stdout); exit(EXIT_FAILURE); } } /* Populate env */ if(INIT_MODE == FALSE) { populate_env(envp); } /* Populate PATH variable * We don't need to calloc() because env_lookup() does this for us. */ PATH = env_lookup("PATH"); /* Populate USERNAME variable */ char* USERNAME = env_lookup("LOGNAME"); /* Handle edge cases */ if((NULL == PATH) && (NULL == USERNAME)) { /* We didn't find either of PATH or USERNAME -- use a generic PATH */ PATH = calloc(MAX_STRING, sizeof(char)); require(PATH != NULL, "Memory initialization of PATH failed\n"); strcpy(PATH, "/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"); } else if(NULL == PATH) { /* We did find a username but not a PATH -- use a generic PATH but with /home/USERNAME */ PATH = calloc(MAX_STRING, sizeof(char)); PATH = strcat(PATH, "/home/"); PATH = strcat(PATH, USERNAME); PATH = strcat(PATH, "/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"); } /* Open the script */ script = fopen(filename, "r"); if(NULL == script) { fputs("The file: ", stderr); fputs(filename, stderr); fputs(" can not be opened!\n", stderr); exit(EXIT_FAILURE); } /* Run the commands */ run_script(script, argv); /* Cleanup */ fclose(script); return EXIT_SUCCESS; } mescc-tools-Release_1.4.0/Kaem/kaem.h000066400000000000000000000027711423361407400173620ustar00rootroot00000000000000/* Copyright (C) 2016-2020 Jeremiah Orians * Copyright (C) 2020 fosslinux * This file is part of mescc-tools. * * mescc-tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mescc-tools 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mescc-tools. If not, see . */ #include #include "../M2libc/bootstrappable.h" /* * DEFINES */ #define FALSE 0 #define TRUE 1 // CONSTANT SUCCESS 0 #define SUCCESS 0 // CONSTANT FAILURE 1 #define FAILURE 1 #define MAX_STRING 4096 #define MAX_ARRAY 256 /* * Here is the token struct. It is used for both the token linked-list and * env linked-list. */ struct Token { /* * For the token linked-list, this stores the token; for the env linked-list * this stores the value of the variable. */ char* value; /* * Used only for the env linked-list. It holds a string containing the * name of the var. */ char* var; /* * This struct stores a node of a singly linked list, store the pointer to * the next node. */ struct Token* next; }; #include "kaem_globals.h" mescc-tools-Release_1.4.0/Kaem/kaem_globals.c000066400000000000000000000021331423361407400210500ustar00rootroot00000000000000/* Copyright (C) 2016-2020 Jeremiah Orians * Copyright (C) 2020 fosslinux * This file is part of mescc-tools. * * mescc-tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mescc-tools 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mescc-tools. If not, see . */ #include "kaem.h" int command_done; int VERBOSE; int VERBOSE_EXIT; int STRICT; int INIT_MODE; int FUZZING; int WARNINGS; char* PATH; /* Token linked-list; stores the tokens of each line */ struct Token* token; /* Env linked-list; stores the environment variables */ struct Token* env; /* Alias linked-list; stores the aliases */ struct Token* alias; mescc-tools-Release_1.4.0/Kaem/kaem_globals.h000066400000000000000000000022251423361407400210570ustar00rootroot00000000000000/* Copyright (C) 2016-2020 Jeremiah Orians * Copyright (C) 2020 fosslinux * This file is part of mescc-tools. * * mescc-tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mescc-tools 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mescc-tools. If not, see . */ extern int command_done; extern int VERBOSE; extern int VERBOSE_EXIT; extern int STRICT; extern int INIT_MODE; extern int FUZZING; extern int WARNINGS; extern char* PATH; /* Token linked-list; stores the tokens of each line */ extern struct Token* token; /* Env linked-list; stores the environment variables */ extern struct Token* env; /* Alias linked-list; stores the aliases */ extern struct Token* alias; mescc-tools-Release_1.4.0/Kaem/makefile000066400000000000000000000027141423361407400177710ustar00rootroot00000000000000## Copyright (C) 2016 Jeremiah Orians ## Copyright (C) 2020 fosslinux ## This file is part of mescc-tools. ## ## mescc-tools is free software: you an redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## mescc-tools 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 General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with mescc-tools. If not, see . # Prevent rebuilding VPATH = ../bin:test/results all: kaem CC=gcc CFLAGS:=$(CFLAGS) -D_GNU_SOURCE -std=c99 -ggdb kaem: kaem.c kaem_globals.c variable.c | bin $(CC) $(CFLAGS) kaem.c \ kaem_globals.c \ variable.c \ ../M2libc/bootstrappable.c \ -o ../bin/kaem # Always run the tests .PHONY: test test: kaem | results ./test.sh # Generate test answers .PHONY: Generate-test-answers Generate-test-answers: sha256sum test/results/* >| test/test.answers # Clean up after ourselves .PHONY: clean clean: rm -rf ../bin/ rm -rf test/results/ results: mkdir -p test/results bin: mkdir -p ../bin DESTDIR:= PREFIX:=/usr/local bindir:=$(DESTDIR)$(PREFIX)/bin .PHONY: install install: kaem mkdir -p $(bindir) cp $^ $(bindir) mescc-tools-Release_1.4.0/Kaem/test.sh000077500000000000000000000041671423361407400176130ustar00rootroot00000000000000#!/bin/bash # Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . echo "Starting kaem tests" LANG=C ../bin/kaem -f "test/test00/kaem.test" >| "test/results/test00-output" LANG=C ../bin/kaem -f "test/test01/kaem.test" >| "test/results/test01-output" LANG=C ../bin/kaem -f "test/test02/kaem.test" >| "test/results/test02-output" LANG=C ../bin/kaem -f "test/test03/kaem.test" >| "test/results/test03-output" LANG=C ../bin/kaem -f "test/test04/kaem.test" >| "test/results/test04-output" 2>&1 LANG=C ../bin/kaem --non-strict -f "test/test05/kaem.test" >| "test/results/test05-output" LANG=C ../bin/kaem -f "test/test06/kaem.test" >| "test/results/test06-output" 2>&1 LANG=C ../bin/kaem -f "test/test07/kaem.test" >| "test/results/test07-output" LANG=C ../bin/kaem -f "test/test08/kaem.test" >| "test/results/test08-output" LANG=C ../bin/kaem -f "test/test09/kaem.test" >| "test/results/test09-output" LANG=C ../bin/kaem -f "test/test10/kaem.test" >| "test/results/test10-output" LANG=C ../bin/kaem -f "test/test11/kaem.test" >| "test/results/test11-output" LANG=C ../bin/kaem -f "test/test12/kaem.test" >| "test/results/test12-output" LANG=C ../bin/kaem -f "test/test13/kaem.test" >| "test/results/test13-output" LANG=C ../bin/kaem -f "test/test14/kaem.test" >| "test/results/test14-output" 2>&1 LANG=C ../bin/kaem -f "test/test15/kaem.test" >| "test/results/test15-output" LANG=C ../bin/kaem -f "test/test16/kaem.test" >| "test/results/test16-output" . ../sha256.sh sha256_check test/test.answers echo "kaem tests complete" mescc-tools-Release_1.4.0/Kaem/test/000077500000000000000000000000001423361407400172445ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/.gitignore000066400000000000000000000000111423361407400212240ustar00rootroot00000000000000results/ mescc-tools-Release_1.4.0/Kaem/test/test.answers000066400000000000000000000030551423361407400216320ustar00rootroot00000000000000e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 test/results/test00-output 27e6f695d734689575e2a063b77668a1fab9c7a83071134630f6a02ebf697592 test/results/test01-output 98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4 test/results/test02-output 5881f8af754d89e4b6f0cc5e65a0654444a83140946a83f7d5941e6236f180d2 test/results/test03-output 8753402793cfecacc5b90b6c7c0f8b351c9be60fd7d07fe18cf4a189bfff16f3 test/results/test04-output 8f434346648f6b96df89dda901c5176b10a6d83961dd3c1ac88b59b2dc327aa4 test/results/test05-output 11b03bec7e7e57151b67cf4d3b38cc5cc9a0469549e104f58b9bf9de82f90c22 test/results/test06-output e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 test/results/test07-output e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 test/results/test08-output 714ef04291d344f7719c207060944b017d4b565ef565b04fbef5ec4c3e8cacb8 test/results/test09-output d857aa87f123be8ca15bab264d2fbc143fe6ca9fa82ebfcc92a3096627c2bfbd test/results/test10-output 95b4340f5a016b59be85be8351cb267642fea01129c8ae40049061301c1b0a95 test/results/test11-output dfb2a6b3ee002a7a82419230acf97563ffe8b84e72f0de074e48453b092da4ad test/results/test12-output 3cf0470e0bba3c7dd743a71f201903fcbd3aed2cf817966e2d127bf10fff66e9 test/results/test13-output 8f434346648f6b96df89dda901c5176b10a6d83961dd3c1ac88b59b2dc327aa4 test/results/test14-output 3b22d4ec57697b461347a0c8d195c854172ae4b8c92b86497f2bbd8add4c4229 test/results/test15-output 472ed61017e76d36a6340ad495bd9e7be5f721d8df65fd4c2caa75e88a412601 test/results/test16-output mescc-tools-Release_1.4.0/Kaem/test/test00/000077500000000000000000000000001423361407400203635ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test00/kaem.test000066400000000000000000000013741423361407400222060ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # This test tests line comments! # There should be no output. mescc-tools-Release_1.4.0/Kaem/test/test01/000077500000000000000000000000001423361407400203645ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test01/kaem.test000066400000000000000000000013671423361407400222110ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test execution of simple commands. printf hi printf hi mescc-tools-Release_1.4.0/Kaem/test/test02/000077500000000000000000000000001423361407400203655ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test02/kaem.test000066400000000000000000000013221423361407400222010ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test echo echo hi mescc-tools-Release_1.4.0/Kaem/test/test03/000077500000000000000000000000001423361407400203665ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test03/kaem.test000066400000000000000000000013441423361407400222060ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test use of set -x set -x printf hi mescc-tools-Release_1.4.0/Kaem/test/test04/000077500000000000000000000000001423361407400203675ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test04/kaem.test000066400000000000000000000013741423361407400222120ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test use of set -e set -e thiscommanddoesnotexist printf hi mescc-tools-Release_1.4.0/Kaem/test/test05/000077500000000000000000000000001423361407400203705ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test05/kaem.test000066400000000000000000000014141423361407400222060ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test non existent commands without set -e thiscommanddoesnotexist printf hi mescc-tools-Release_1.4.0/Kaem/test/test06/000077500000000000000000000000001423361407400203715ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test06/kaem.test000066400000000000000000000014221423361407400222060ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test use of multiple arguments with set set -ex thiscommanddoesnotexist printf hi mescc-tools-Release_1.4.0/Kaem/test/test07/000077500000000000000000000000001423361407400203725ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test07/kaem.test000066400000000000000000000014201423361407400222050ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # This is meant to test pwd. # But I don't have a very good way to test it yet... mescc-tools-Release_1.4.0/Kaem/test/test08/000077500000000000000000000000001423361407400203735ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test08/kaem.test000066400000000000000000000013411423361407400222100ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test adding of an envar VAR=text mescc-tools-Release_1.4.0/Kaem/test/test09/000077500000000000000000000000001423361407400203745ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test09/kaem.test000066400000000000000000000013431423361407400222130ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test RAW strings echo "raw string" mescc-tools-Release_1.4.0/Kaem/test/test10/000077500000000000000000000000001423361407400203645ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test10/kaem.test000066400000000000000000000015011423361407400221770ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test simple variable substitution VAR=text ANOTHER=more echo text-${VAR}-${ANOTHER}-text ../bin/kaem -f test/test10/subkaem.test mescc-tools-Release_1.4.0/Kaem/test/test10/subkaem.test000066400000000000000000000014331423361407400227150ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test simple variable substitution, passed to another kaem echo text-${VAR}-${ANOTHER}-text mescc-tools-Release_1.4.0/Kaem/test/test11/000077500000000000000000000000001423361407400203655ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test11/kaem.test000066400000000000000000000014231423361407400222030ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test variable subsitution with :- where the var exists VAR=exists echo ${VAR:-not} mescc-tools-Release_1.4.0/Kaem/test/test12/000077500000000000000000000000001423361407400203665ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test12/kaem.test000066400000000000000000000014251423361407400222060ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test variable subsitution with :- where the variable does not exist echo ${VAR:-not} mescc-tools-Release_1.4.0/Kaem/test/test13/000077500000000000000000000000001423361407400203675ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test13/kaem.test000066400000000000000000000013471423361407400222120ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test substitution of $@ echo $@ -- foo mescc-tools-Release_1.4.0/Kaem/test/test14/000077500000000000000000000000001423361407400203705ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test14/kaem.test000066400000000000000000000013531423361407400222100ustar00rootroot00000000000000# Copyright (C) 2020 fosslinux # This file is part of mescc-tools. # # mescc-tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . # # Test end-of-line escapes printf \ "hi" mescc-tools-Release_1.4.0/Kaem/test/test15/000077500000000000000000000000001423361407400203715ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test15/kaem.test000066400000000000000000000001211423361407400222010ustar00rootroot00000000000000VAR=test ANOTHER=test2 echo ${VAR} unset VAR ANOTHER echo ${VAR} echo ${ANOTHER} mescc-tools-Release_1.4.0/Kaem/test/test16/000077500000000000000000000000001423361407400203725ustar00rootroot00000000000000mescc-tools-Release_1.4.0/Kaem/test/test16/kaem.test000066400000000000000000000000351423361407400222060ustar00rootroot00000000000000echo \"test\" echo "\"test2" mescc-tools-Release_1.4.0/Kaem/variable.c000066400000000000000000000176551423361407400202340ustar00rootroot00000000000000/* * Copyright (C) 2020 fosslinux * This file is part of mescc-tools. * * mescc-tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mescc-tools 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mescc-tools. If not, see . */ #include #include #include #include #include "kaem.h" /* Prototypes from other files */ int array_length(char** array); char* env_lookup(char* variable); /* * VARIABLE HANDLING FUNCTIONS */ /* Substitute a variable into n->value */ int run_substitution(char* var_name, struct Token* n) { char* value = env_lookup(var_name); /* If there is nothing to substitute, don't substitute anything! */ if(value != NULL) { char* s = calloc(MAX_STRING, sizeof(char)); s = strcat(s, n->value); s = strcat(s, value); n->value = s; return TRUE; } return FALSE; } /* Handle ${var:-text} format of variables - i.e. ifset format */ int variable_substitute_ifset(char* input, struct Token* n, int index) { /* * In ${var:-text} format, we evaluate like follows. * If var is set as an envar, then we substitute the contents of that * envar. If it is not set, we substitute alternative text. * * In this function, we assume that input is the raw token, * n->value is everything already done in variable_substitute, * index is where we are up to in input. offset is for n->value. */ /* * Check if we should even be performing this function. * We perform this function when we come across ${var:-text} syntax. */ int index_old = index; int perform = FALSE; int input_length = strlen(input); while(index < input_length) { /* Loop over each character */ if(input[index] == ':' && input[index + 1] == '-') { /* Yes, this is (most likely) ${var:-text} format. */ perform = TRUE; break; } index = index + 1; } /* Don't perform it if we shouldn't */ if(perform == FALSE) return index_old; index = index_old; /* * Get offset. * offset is the difference between the index of the variable we write to * in the following blocks and input. * This stays relatively constant. */ int offset = index; /* Get the variable name */ char* var_name = calloc(MAX_STRING, sizeof(char)); require(var_name != NULL, "Memory initialization of var_name in variable_substitute_ifset failed\n"); while(input[index] != ':') { /* Copy into var_name until :- */ var_name[index - offset] = input[index]; index = index + 1; } /* Skip over :- */ index = index + 2; offset = index; /* Get the alternative text */ char* text = calloc(MAX_STRING, sizeof(char)); require(text != NULL, "Memory initialization of text in variable_substitute_ifset failed\n"); while(input[index] != '}') { /* Copy into text until } */ require(input_length > index, "IMPROPERLY TERMINATED VARIABLE\nABORTING HARD\n"); text[index - offset] = input[index]; index = index + 1; } /* Do the substitution */ if(run_substitution(var_name, n) == FALSE) { /* The variable was not found. Substitute the alternative text. */ char* s = calloc(MAX_STRING, sizeof(char)); s = strcat(s, n->value); s = strcat(s, text); n->value = s; } return index; } /* Controls substitution for ${variable} and derivatives */ int variable_substitute(char* input, struct Token* n, int index) { /* NOTE: index is the pos of input */ index = index + 1; /* We don't want the { */ /* * Check for "special" types * If we do find a special type we delegate the substitution to it * and return here; as we are done... there's nothing more do do in * that case. */ int index_old = index; index = variable_substitute_ifset(input, n, index); if(index != index_old) return index; /* Reset index */ index = index_old; /* * If we reach here it is a normal substitution * Let's do it! */ /* Initialize var_name and offset */ char* var_name = calloc(MAX_STRING, sizeof(char)); require(var_name != NULL, "Memory initialization of var_name in variable_substitute failed\n"); int offset = index; /* Get the variable name */ int substitute_done = FALSE; char c; while(substitute_done == FALSE) { c = input[index]; require(MAX_STRING > index, "LINE IS TOO LONG\nABORTING HARD\n"); if(EOF == c || '\n' == c || index > strlen(input)) { /* We never should hit EOF, EOL or run past the end of the line while collecting a variable */ fputs("IMPROPERLY TERMINATED VARIABLE!\nABORTING HARD\n", stderr); exit(EXIT_FAILURE); } else if('\\' == c) { /* Drop the \ - poor mans escaping. */ index = index + 1; } else if('}' == c) { /* End of variable name */ substitute_done = TRUE; } else { var_name[index - offset] = c; index = index + 1; } } /* Substitute the variable */ run_substitution(var_name, n); return index; } /* Function to concatenate all command line arguments */ void variable_all(char** argv, struct Token* n) { fflush(stdout); /* index refernences the index of n->value, unlike other functions */ int index = 0; int argv_length = array_length(argv); int i = 0; char* argv_element = calloc(MAX_STRING, sizeof(char)); char* hold = argv[i]; n->value = argv_element; /* Assuming the form kaem -f script or kaem -f script -- 123 we want matching results to bash, so skip the kaem, -f and script */ while(!match("--", hold)) { i = i + 1; hold = argv[i]; if(argv_length == i) break; } /* put i = i + 1 in the for initialization to skip past the -- */ for(; i < argv_length; i = i + 1) { /* Ends up with (n->value) (argv[i]) */ /* If we don't do this we get jumbled results in M2-Planet */ hold = argv[i]; strcpy(argv_element + index, hold); index = index + strlen(hold); /* Add space on the end */ n->value[index] = ' '; index = index + 1; } /* Remove trailing space */ index = index - 1; n->value[index] = 0; } /* Function controlling substitution of variables */ void handle_variables(char** argv, struct Token* n) { /* NOTE: index is the position of input */ int index = 0; /* Create input */ char* input = calloc(MAX_STRING, sizeof(char)); require(input != NULL, "Memory initialization of input in collect_variable failed\n"); strcpy(input, n->value); /* Reset n->value */ n->value = calloc(MAX_STRING, sizeof(char)); require(n->value != NULL, "Memory initialization of n->value in collect_variable failed\n"); /* Copy everything up to the $ */ /* * TODO: Not need allocation of input before this check if there is no * variable in it. */ while(input[index] != '$') { if(input[index] == 0) { /* No variable in it */ n->value = input; return; /* We don't need to do anything more */ } n->value[index] = input[index]; index = index + 1; } /* Must be outside the loop */ int offset; substitute: index = index + 1; /* We are uninterested in the $ */ /* Run the substitution */ if(input[index] == '{') { /* Handle everything ${ related */ index = variable_substitute(input, n, index); index = index + 1; /* We don't want the closing } */ } else if(input[index] == '@') { /* Handles $@ */ index = index + 1; /* We don't want the @ */ variable_all(argv, n); } else { /* We don't know that */ fputs("IMPROPERLY USED VARIABLE!\nOnly ${foo} and $@ format are accepted at this time.\nABORTING HARD\n", stderr); exit(EXIT_FAILURE); } offset = strlen(n->value) - index; /* Copy everything from the end of the variable to the end of the token */ while(input[index] != 0) { if(input[index] == '$') { /* We have found another variable */ fflush(stdout); goto substitute; } n->value[index + offset] = input[index]; index = index + 1; } } mescc-tools-Release_1.4.0/M1-macro.c000066400000000000000000000460131423361407400171340ustar00rootroot00000000000000/* -*- c-file-style: "linux";indent-tabs-mode:t -*- */ /* Copyright (C) 2016 Jeremiah Orians * Copyright (C) 2017 Jan Nieuwenhuizen * This file is part of mescc-tools. * * mescc-tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mescc-tools 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mescc-tools. If not, see . */ #include #include #include #include "M2libc/bootstrappable.h" /* Internal processing Constants */ // CONSTANT max_string 4096 #define max_string 4096 // CONSTANT PROCESSED 1 #define PROCESSED 1 // CONSTANT STR 2 #define STR 2 // CONSTANT NEWLINE 3 #define NEWLINE 3 /* Unique code for each architecture */ // CONSTANT KNIGHT 0 #define KNIGHT 0 // CONSTANT X86 3 #define X86 0x03 // CONSTANT AMD64 62 #define AMD64 0x3E // CONSTANT ARMV7L 40 #define ARMV7L 0x28 // CONSTANT AARM64 183 #define AARM64 0xB7 // CONSTANT PPC64LE 21 #define PPC64LE 0x15 // CONSTANT RISCV32 243 #define RISCV32 0xF3 // CONSTANT RISCV64 65779 #define RISCV64 0x100F3 /* Because RISC-V unlike all other architectures does get a seperate e_machine when changing from 32 to 64bit */ /* How do you want that output? */ // CONSTANT HEX 16 #define HEX 16 // CONSTANT OCTAL 8 #define OCTAL 8 // CONSTANT BINARY 2 #define BINARY 2 /* Imported from stringify.c */ int stringify(char* s, int digits, int divisor, int value, int shift); void LittleEndian(char* start, int ByteMode); struct blob { struct blob* next; int type; char* Text; char* Expression; struct blob* hash_next; }; struct Token { struct Token* next; struct blob* contents; char* filename; int linenumber; }; /* Globals */ FILE* source_file; FILE* destination_file; int BigEndian; int ByteMode; int Architecture; int linenumber; struct Token* token_list; struct blob* blob_list; struct blob* define_blob; struct blob* newline_blob; int blob_count; char* SCRATCH; struct blob** hash_table; void line_error(char* filename, int linenumber) { fputs(filename, stderr); fputs(":", stderr); fputs(int2str(linenumber,10, FALSE), stderr); fputs(" :", stderr); } void ClearScratch() { int i = 0; int c = SCRATCH[i]; while(0 != c) { SCRATCH[i] = 0; i = i + 1; c = SCRATCH[i]; } } int GetHash(char* s) { int i = 5381; while(0 != s[0]) { i = (i << 5) + i + s[0]; s = s + 1; } return i & 0xFFFF; } struct blob* FindBlob() { int hash = GetHash(SCRATCH); struct blob* i = hash_table[hash]; while(NULL != i) { if(match(SCRATCH, i->Text)) return i; i = i->hash_next; } return NULL; } void AddHash(struct blob* a, char* s) { int i = GetHash(s); a->hash_next = hash_table[i]; hash_table[i] = a; } void NewBlob(int size) { blob_count = blob_count + 1; struct blob* a = calloc(1, sizeof(struct blob)); require(NULL != a, "Exhausted available memory\n"); a->Text = calloc(size + 1, sizeof(char)); require(NULL != a->Text, "Exhausted available memory\n"); int i = 0; while(i <= size) { a->Text[i] = SCRATCH[i]; i = i + 1; } a->next = blob_list; blob_list = a; AddHash(a, SCRATCH); } struct Token* newToken(char* filename, int linenumber) { struct Token* p; p = calloc (1, sizeof (struct Token)); require(NULL != p, "Exhausted available memory\n"); p->filename = filename; p->linenumber = linenumber; return p; } struct Token* reverse_list(struct Token* head) { struct Token* root = NULL; struct Token* next; while(NULL != head) { next = head->next; head->next = root; root = head; head = next; } return root; } void purge_lineComment() { int c = fgetc(source_file); while(!in_set(c, "\n\r")) { if(EOF == c) break; c = fgetc(source_file); } } struct Token* append_newline(struct Token* head, char* filename) { linenumber = linenumber + 1; if(NULL == head) return NULL; if(NEWLINE == head->contents->type) {/* Don't waste whitespace*/ return head; } struct Token* lf = newToken(filename, linenumber); lf->contents = newline_blob; lf->next = head; return lf; } struct Token* store_atom(struct Token* head, char c, char* filename) { ClearScratch(); int ch = c; int i = 0; do { SCRATCH[i] = ch; ch = fgetc(source_file); i = i + 1; if(i >= max_string) { fputs("storing atom of size larger than max_string\n", stderr); line_error(filename, linenumber); fputc('\n', stderr); exit(EXIT_FAILURE); } if(EOF == ch) break; } while (!in_set(ch, "\t\n ")); head->contents = FindBlob(); if(NULL == head->contents) { NewBlob(i); head->contents = blob_list; } if('\n' == ch) { return append_newline(head, filename); } return head; } struct blob* store_string(char c, char* filename) { ClearScratch(); int ch = c; int i = 0; do { SCRATCH[i] = ch; i = i + 1; if('\n' == ch) linenumber = linenumber + 1; ch = fgetc(source_file); require(EOF != ch, "Unmatched \"!\n"); if(max_string == i) { line_error(filename, linenumber); fputs("String: ", stderr); fputs(SCRATCH, stderr); fputs(" exceeds max string size\n", stderr); exit(EXIT_FAILURE); } } while(ch != c); struct blob* a = FindBlob(); if(NULL == a) { NewBlob(i); a = blob_list; a->type = STR; } return a; } struct Token* Tokenize_Line(struct Token* head, char* filename) { int c; struct Token* p; linenumber = 1; do { restart: c = fgetc(source_file); if(in_set(c, ";#")) { purge_lineComment(); head = append_newline(head, filename); goto restart; } if(in_set(c, "\t ")) { goto restart; } if('\n' == c) { head = append_newline(head, filename); goto restart; } if(EOF == c) { head = append_newline(head, filename); goto done; } p = newToken(filename, linenumber); p->next = head; if(in_set(c, "'\"")) { p->contents = store_string(c, filename); } else { p = store_atom(p, c, filename); } head = p; } while(TRUE); done: return head; } void line_macro(struct Token* p) { struct Token* i; for(i = p; NULL != i; i = i->next) { if(define_blob == i->contents) { require(NULL != i->next, "Macro name must exist\n"); require(NULL != i->next->next, "Macro value must exist\n"); if(PROCESSED == i->next->contents->type) { line_error(i->filename, i->linenumber); fputs("Multiple definitions for macro ", stderr); fputs(i->next->contents->Text, stderr); fputs("\n", stderr); exit(EXIT_FAILURE); } i->contents = newline_blob; if (STR == i->next->next->contents->type) { i->contents->Expression = i->next->next->contents->Text + 1; } else { i->next->contents->Expression = i->next->next->contents->Text; } i->next = i->next->next->next; } } } void hexify_string(struct blob* p) { char* table = "0123456789ABCDEF"; int i = strlen(p->Text); int size; if(HEX == ByteMode) size = (((i << 1) + i) + 12); else if(OCTAL == ByteMode) size = (i << 2) + 1; else if(BINARY == ByteMode) size = (i << 3) + i + 1; else size = 1; require(1 != size, "hexify_string lacked a valid bytemode\n"); char* d = calloc(size, sizeof(char)); require(NULL != d, "Exhausted available memory\n"); p->Expression = d; char* S = p->Text; if((KNIGHT == Architecture) && (HEX == ByteMode)) { i = (((((i - 1) >> 2) + 1) << 3) + i); while( 0 < i) { i = i - 1; d[i] = '0'; } } if(HEX == ByteMode) { while(0 != S[0]) { S = S + 1; d[0] = table[S[0] >> 4]; d[1] = table[S[0] & 0xF]; d[2] = ' '; d = d + 3; } } else if(OCTAL == ByteMode) { while(0 != S[0]) { S = S + 1; d[0] = table[S[0] >> 6]; d[1] = table[(S[0] >> 3) & 0x7]; d[2] = table[S[0] & 0x7]; d[3] = ' '; d = d + 4; } } else if(BINARY == ByteMode) { while(0 != S[0]) { S = S + 1; d[0] = table[S[0] >> 7]; d[1] = table[(S[0] >> 6) & 0x1]; d[2] = table[(S[0] >> 5) & 0x1]; d[3] = table[(S[0] >> 4) & 0x1]; d[4] = table[(S[0] >> 3) & 0x1]; d[5] = table[(S[0] >> 2) & 0x1]; d[6] = table[(S[0] >> 1) & 0x1]; d[7] = table[S[0] & 0x1]; d[8] = ' '; d = d + 9; } } } void process_string(struct blob* p) { struct blob* i; for(i = p; NULL != i; i = i->next) { if(STR == i->type) { if('\'' == i->Text[0]) { i->Expression = i->Text + 1; } else if('"' == i->Text[0]) { hexify_string(i); } } } } char* pad_nulls(int size, char* nil) { if(0 == size) return nil; require(size > 0, "negative null padding not possible\n"); if(HEX == ByteMode) size = size * 2; else if (OCTAL == ByteMode) size = size * 3; else if (BINARY == ByteMode) size = size * 8; char* s = calloc(size + 1, sizeof(char)); require(NULL != s, "Exhausted available memory\n"); int i = 0; while(i < size) { s[i] = '0'; i = i + 1; } return s; } void preserve_other(struct blob* p) { struct blob* i; char c; for(i = p; NULL != i; i = i->next) { if((NULL == i->Expression) && !(i->type & PROCESSED)) { c = i->Text[0]; if(in_set(c, "!@$~%&:^")) { i->Expression = i->Text; } else if('<' == c) { i->Expression = pad_nulls(strtoint(i->Text + 1), i->Text); } } } } void bound_values(int displacement, int number_of_bytes, int low, int high) { if((high < displacement) || (displacement < low)) { fputs("A displacement of ", stderr); fputs(int2str(displacement, 10, TRUE), stderr); fputs(" does not fit in ", stderr); fputs(int2str(number_of_bytes, 10, TRUE), stderr); fputs(" bytes\n", stderr); exit(EXIT_FAILURE); } } void range_check(int displacement, int number_of_bytes) { if(4 == number_of_bytes) return; else if(3 == number_of_bytes) { bound_values(displacement, number_of_bytes, -8388608, 16777216); return; } else if(2 == number_of_bytes) { bound_values(displacement, number_of_bytes, -32768, 65535); return; } else if(1 == number_of_bytes) { bound_values(displacement, number_of_bytes, -128, 255); return; } fputs("Received an invalid number of bytes in range_check\n", stderr); exit(EXIT_FAILURE); } char* express_number(int value, char c) { char* ch = calloc(42, sizeof(char)); require(NULL != ch, "Exhausted available memory\n"); int size; int number_of_bytes; int shift; if('!' == c) { number_of_bytes = 1; value = value & 0xFF; } else if('@' == c) { number_of_bytes = 2; value = value & 0xFFFF; } else if('~' == c) { number_of_bytes = 3; value = value & 0xFFFFFF; } else if('%' == c) { number_of_bytes = 4; value = value & 0xFFFFFFFF; } else { fputs("Given symbol ", stderr); fputc(c, stderr); fputs(" to express immediate value ", stderr); fputs(int2str(value, 10, TRUE), stderr); fputc('\n', stderr); exit(EXIT_FAILURE); } range_check(value, number_of_bytes); if(HEX == ByteMode) { size = number_of_bytes * 2; shift = 4; } else if(OCTAL == ByteMode) { size = number_of_bytes * 3; shift = 3; } else if(BINARY == ByteMode) { size = number_of_bytes * 8; shift = 1; } else { fputs("Got invalid ByteMode in express_number\n", stderr); exit(EXIT_FAILURE); } stringify(ch, size, ByteMode, value, shift); if(!BigEndian) LittleEndian(ch, ByteMode); return ch; } char* express_word(int value, char c) { char* s = calloc(43, sizeof(char)); s[0] = '.'; char* ch = s + 1; require(NULL != ch, "Exhausted available memory\n"); int size; int shift; int immediate; if('!' == c) { /* Corresponds to RISC-V I format */ immediate = (value & 0xFFF) << 20; } else if('@' == c) { /* Corresponds to RISC-V S format */ immediate = ((value & 0x1F) << 7) | ((value & 0xFE0) << (31 - 11)); } else if('~' == c) { /* Corresponds with RISC-V U format */ if ((value & 0xFFF) < 0x800) { immediate = value & 0xFFFFF000; } else { immediate = (value & 0xFFFFF000) + 0x1000; } } else if('%' == c) { /* provides an option for 32bit immediate constants */ immediate = value & 0xFFFFFFFF; /* Drop the leading . */ ch = s; } else { fputs("Given symbol ", stderr); fputc(c, stderr); fputs(" to express immediate value ", stderr); fputs(int2str(value, 10, TRUE), stderr); fputc('\n', stderr); exit(EXIT_FAILURE); } if(HEX == ByteMode) { size = 4 * 2; shift = 4; } else if(OCTAL == ByteMode) { size = 4 * 3; shift = 3; } else if(BINARY == ByteMode) { size = 4 * 8; shift = 1; } else { fputs("Got invalid ByteMode in express_number\n", stderr); exit(EXIT_FAILURE); } stringify(ch, size, ByteMode, immediate, shift); if(!BigEndian) LittleEndian(ch, ByteMode); return s; } void eval_immediates(struct blob* p) { struct blob* i; int value; for(i = p; NULL != i; i = i->next) { if(PROCESSED == i->type) continue; else if(NEWLINE == i->type) continue; else if('<' == i->Text[0]) continue; else if(NULL == i->Expression) { if((X86 == Architecture) || (AMD64 == Architecture) || (ARMV7L == Architecture) || (AARM64 == Architecture) || (PPC64LE == Architecture)) { if(in_set(i->Text[0], "%~@!")) { value = strtoint(i->Text + 1); if(('0' == i->Text[1]) || (0 != value)) { i->Expression = express_number(value, i->Text[0]); } } } else if((RISCV32 == Architecture) || (RISCV64 == Architecture)) { if(in_set(i->Text[0], "%~@!")) { value = strtoint(i->Text + 1); if(('0' == i->Text[1]) || (0 != value)) { i->Expression = express_word(value, i->Text[0]); } } } else if(KNIGHT == Architecture) { value = strtoint(i->Text); if(('0' == i->Text[0]) || (0 != value)) { i->Expression = express_number(value, '@'); } } else { fputs("Unknown architecture received in eval_immediates\n", stderr); exit(EXIT_FAILURE); } } } } void print_hex(struct Token* p) { struct Token* i; for(i = p; NULL != i; i = i->next) { if(NEWLINE == i->contents->type) { if(NULL == i->next) fputc('\n', destination_file); else if(NEWLINE != i->next->contents->type) fputc('\n', destination_file); } else if(NULL != i->contents->Expression) { fputs(i->contents->Expression, destination_file); if(NEWLINE != i->next->contents->type) fputc(' ', destination_file); } else { line_error(i->filename, i->linenumber); fputs("Received invalid other; ", stderr); fputs(i->contents->Text, stderr); fputs("\n", stderr); exit(EXIT_FAILURE); } } } /* Standard C main program */ int main(int argc, char **argv) { BigEndian = TRUE; Architecture = KNIGHT; destination_file = stdout; ByteMode = HEX; char* filename; char* arch; blob_count = 2; hash_table = calloc(65537, sizeof(struct blob*)); /* Create newline blob */ newline_blob = calloc(1, sizeof(struct blob)); newline_blob->Text = "\n"; newline_blob->Expression = "\n"; newline_blob->type = NEWLINE; AddHash(newline_blob, "\n"); /* Start the blob list with DEFINE and newline */ blob_list = calloc(1, sizeof(struct blob)); blob_list->Text = "DEFINE"; define_blob = blob_list; blob_list->next = newline_blob; AddHash(define_blob, "DEFINE"); /* Initialize scratch */ SCRATCH = calloc(max_string + 1, sizeof(char)); int option_index = 1; while(option_index <= argc) { if(NULL == argv[option_index]) { option_index = option_index + 1; } else if(match(argv[option_index], "--BigEndian")) { fputs("--BigEndian is now depreciated and replaced by --big-endian\nAnd will stop working in the next release\n", stderr); BigEndian = TRUE; option_index = option_index + 1; } else if(match(argv[option_index], "--big-endian")) { BigEndian = TRUE; option_index = option_index + 1; } else if(match(argv[option_index], "--LittleEndian")) { fputs("--LittleEndian is now depreciated and replaced by --little-endian\nAnd will stop working in the next release\n", stderr); BigEndian = FALSE; option_index = option_index + 1; } else if(match(argv[option_index], "--little-endian")) { BigEndian = FALSE; option_index = option_index + 1; } else if(match(argv[option_index], "-A") || match(argv[option_index], "--architecture")) { arch = argv[option_index + 1]; if(match("knight-native", arch) || match("knight-posix", arch)) Architecture = KNIGHT; else if(match("x86", arch)) Architecture = X86; else if(match("amd64", arch)) Architecture = AMD64; else if(match("armv7l", arch)) Architecture = ARMV7L; else if(match("aarch64", arch)) Architecture = AARM64; else if(match("ppc64le", arch)) Architecture = PPC64LE; else if(match("riscv32", arch)) Architecture = RISCV32; else if(match("riscv64", arch)) Architecture = RISCV64; else { fputs("Unknown architecture: ", stderr); fputs(arch, stderr); fputs(" know values are: knight-native, knight-posix, x86, amd64, armv7l, aarch64, ppc64le, riscv32 and riscv64", stderr); exit(EXIT_FAILURE); } option_index = option_index + 2; } else if(match(argv[option_index], "-b") || match(argv[option_index], "--binary")) { ByteMode = BINARY; option_index = option_index + 1; } else if(match(argv[option_index], "-h") || match(argv[option_index], "--help")) { fputs("Usage: ", stderr); fputs(argv[0], stderr); fputs(" --file FILENAME1 {-f FILENAME2} (--big-endian|--little-endian) ", stderr); fputs("[--architecture name]\nArchitectures: knight-native, knight-posix, x86, amd64, armv7, riscv32 and riscv64\n", stderr); fputs("To leverage octal or binary output: --octal, --binary\n", stderr); exit(EXIT_SUCCESS); } else if(match(argv[option_index], "-f") || match(argv[option_index], "--file")) { filename = argv[option_index + 1]; source_file = fopen(filename, "r"); if(NULL == source_file) { fputs("The file: ", stderr); fputs(argv[option_index + 1], stderr); fputs(" can not be opened!\n", stderr); exit(EXIT_FAILURE); } token_list = Tokenize_Line(token_list, filename); fclose(source_file); option_index = option_index + 2; } else if(match(argv[option_index], "-o") || match(argv[option_index], "--output")) { destination_file = fopen(argv[option_index + 1], "w"); if(NULL == destination_file) { fputs("The file: ", stderr); fputs(argv[option_index + 1], stderr); fputs(" can not be opened!\n", stderr); exit(EXIT_FAILURE); } option_index = option_index + 2; } else if(match(argv[option_index], "-O") || match(argv[option_index], "--octal")) { ByteMode = OCTAL; option_index = option_index + 1; } else if(match(argv[option_index], "-V") || match(argv[option_index], "--version")) { fputs("M1 1.4.0\n", stdout); exit(EXIT_SUCCESS); } else { fputs("Unknown option\n", stderr); exit(EXIT_FAILURE); } } if(NULL == token_list) { fputs("Either no input files were given or they were empty\n", stderr); exit(EXIT_FAILURE); } token_list = reverse_list(token_list); line_macro(token_list); process_string(blob_list); eval_immediates(blob_list); preserve_other(blob_list); print_hex(token_list); fclose(destination_file); return EXIT_SUCCESS; } mescc-tools-Release_1.4.0/M2libc/000077500000000000000000000000001423361407400165205ustar00rootroot00000000000000mescc-tools-Release_1.4.0/README.md000066400000000000000000000036301423361407400166710ustar00rootroot00000000000000## Copyright (C) 2017 Jeremiah Orians ## This file is part of mescc-tools. ## ## mescc-tools is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## mescc-tools 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 General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with mescc-tools. If not, see . The master repository for this work is located at: https://savannah.nongnu.org/projects/mescc-tools # If you wish to contribute: pull requests can be made at https://github.com/oriansj/mescc-tools and https://gitlab.com/janneke/mescc-tools or patches/diffs can be sent via email to Jeremiah (at) pdp10 [dot] guru or join us on libera.chat's #bootstrappable These are a collection of tools written for use in bootstrapping # blood-elf A tool for generating ELF debug tables in M1-macro format from M1-macro assembly files # exec_enable A tool for marking files as executable, for systems that don't have chmod # get_machine A tool for identifying what hardware architecture you are running on # kaem A minimal shell script build tool that can be used for running shell scripts on systems that lack any shells. # hex2_linker The trivially bootstrappable linker that is designed to be introspectable by humans and should you so desire assemble hex programs that you write. # M1-macro The universal Macro assembler that can target any reasonable hardware architecture. With these tools on your system, you can always bootstrap real programs; even in the most catastrophic of situations, provided you keep your cool. mescc-tools-Release_1.4.0/blood-elf.c000066400000000000000000000332421423361407400174230ustar00rootroot00000000000000/* -*- c-file-style: "linux";indent-tabs-mode:t -*- */ /* Copyright (C) 2017 Jeremiah Orians * Copyright (C) 2017 Jan Nieuwenhuizen * This file is part of mescc-tools * * mescc-tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mescc-tools 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mescc-tools. If not, see . */ #include #include #include #include #include #include "M2libc/bootstrappable.h" // CONSTANT max_string 4096 #define max_string 4096 int BITSIZE; int BigEndian; // CONSTANT HEX 16 #define HEX 16 // CONSTANT OCTAL 8 #define OCTAL 8 // CONSTANT BINARY 2 #define BINARY 2 /* Strings needed for constants */ char* zero_8; char* zero_16; char* zero_32; char* one_16; char* one_32; char* two_8; char* two_32; char* three_32; char* six_32; char* sixteen_32; char* twentyfour_32; /* Imported from stringify.c */ int stringify(char* s, int digits, int divisor, int value, int shift); void LittleEndian(char* start, int ByteMode); struct entry { struct entry* next; char* name; }; FILE* output; struct entry* jump_table; int count; char* entry; void consume_token(FILE* source_file, char* s) { int i = 0; int c = fgetc(source_file); require(EOF != c, "Can not have an EOF token\n"); do { s[i] = c; i = i + 1; require(max_string > i, "Token exceeds token length restriction\n"); c = fgetc(source_file); if(EOF == c) break; } while(!in_set(c, " \t\n>")); } void storeLabel(FILE* source_file) { struct entry* entry = calloc(1, sizeof(struct entry)); /* Prepend to list */ entry->next = jump_table; jump_table = entry; /* Store string */ entry->name = calloc((max_string + 1), sizeof(char)); consume_token(source_file, entry->name); count = count + 1; } void line_Comment(FILE* source_file) { int c = fgetc(source_file); while(!in_set(c, "\n\r")) { if(EOF == c) break; c = fgetc(source_file); } } void purge_string(FILE* source_file) { int c = fgetc(source_file); while((EOF != c) && ('"' != c)) { c = fgetc(source_file); } } void first_pass(struct entry* input) { if(NULL == input) return; first_pass(input->next); FILE* source_file = fopen(input->name, "r"); if(NULL == source_file) { fputs("The file: ", stderr); fputs(input->name, stderr); fputs(" can not be opened!\n", stderr); exit(EXIT_FAILURE); } int c; for(c = fgetc(source_file); EOF != c; c = fgetc(source_file)) { /* Check for and deal with label */ if(58 == c) { storeLabel(source_file); } /* Check for and deal with line comments */ else if (c == '#' || c == ';') { line_Comment(source_file); } else if ('"' == c) { purge_string(source_file); } } fclose(source_file); } void output_string_table(struct entry* node) { fputs("\n# Generated string table\n:ELF_str\n", output); fputs(zero_8, output); fputs("\t# NULL string\n", output); struct entry* i; for(i = node; NULL != i; i = i->next) { fputs(":ELF_str_", output); fputs(i->name, output); fputs("\t\"", output); fputs(i->name, output); fputs("\"\n", output); } fputs("# END Generated string table\n\n", output); } void output_symbol_table(struct entry* node) { fputs("\n# Generated symbol table\n:ELF_sym\n# Required NULL symbol entry\n", output); if(64 == BITSIZE) { fputs(zero_32, output); fputs("\t# st_name\n", output); fputs(zero_8, output); fputs("\t# st_info\n", output); fputs(zero_8, output); fputs("\t# st_other\n", output); fputs(one_16, output); fputs("\t# st_shndx\n", output); fputs(zero_32, output); fputc(' ', output); fputs(zero_32, output); fputs("\t# st_value\n", output); fputs(zero_32, output); fputc(' ', output); fputs(zero_32, output); fputs("\t# st_size\n\n", output); } else { fputs(zero_32, output); fputs("\t# st_name\n", output); fputs(zero_32, output); fputs("\t# st_value\n", output); fputs(zero_32, output); fputs("\t# st_size\n", output); fputs(zero_8, output); fputs("\t# st_info\n", output); fputs(zero_8, output); fputs("\t# st_other\n", output); fputs(one_16, output); fputs("\t# st_shndx\n\n", output); } struct entry* i; for(i = node; NULL != i; i = i->next) { fputs("%ELF_str_", output); fputs(i->name, output); fputs(">ELF_str\t# st_name\n", output); if(64 == BITSIZE) { fputs(two_8, output); fputs("\t# st_info (FUNC)\n", output); if(('_' == i->name[0]) && !match(entry, i->name)) { fputs(two_8, output); fputs("\t# st_other (hidden)\n", output); } else { fputs(zero_8, output); fputs("\t# st_other (other)\n", output); } fputs(one_16, output); fputs("\t# st_shndx\n", output); fputs("&", output); fputs(i->name, output); fputc(' ', output); fputs(zero_32, output); fputs("\t# st_value\n", output); fputs(zero_32, output); fputc(' ', output); fputs(zero_32, output); fputs("\t# st_size (unknown size)\n\n", output); } else { fputs("&", output); fputs(i->name, output); fputs("\t#st_value\n", output); fputs(zero_32, output); fputs("\t# st_size (unknown size)\n", output); fputs(two_8, output); fputs("\t# st_info (FUNC)\n", output); if(('_' == i->name[0]) && !match(entry, i->name)) { fputs(two_8, output); fputs("\t# st_other (hidden)\n", output); } else { fputs(zero_8, output); fputs("\t# st_other (default)\n", output); } fputs(one_16, output); fputs("\t# st_shndx\n\n", output); } } fputs("# END Generated symbol table\n", output); } struct entry* reverse_list(struct entry* head) { struct entry* root = NULL; struct entry* next; while(NULL != head) { next = head->next; head->next = root; root = head; head = next; } return root; } void write_int(char* field, char* label) { fputs(field, output); fputs("\t#", output); fputs(label, output); fputc('\n', output); } void write_register(char* field, char* label) { /* $field section in the section headers are different size for 32 and 64bits */ /* The below is broken for BigEndian */ fputs(field, output); if(64 == BITSIZE) { fputc(' ', output); fputs(zero_32, output); } fputs("\t#", output); fputs(label, output); fputc('\n', output); } void write_section(char* label, char* name, char* type, char* flags, char* address, char* offset, char* size, char* link, char* info, char* entry) { /* Write label */ fputc('\n', output); fputs(label, output); fputc('\n', output); write_int(name, "sh_name"); write_int(type, "sh_type"); write_register(flags, "sh_flags"); write_register(address, "sh_addr"); write_register(offset, "sh_offset"); write_register(size, "sh_size"); write_int(link, "sh_link"); /* Deal with the ugly case of stubs */ fputs(info, output); fputs("\t#sh_info\n", output); /* Alignment section in the section headers are different size for 32 and 64bits */ /* The below is broken for BigEndian */ if(64 == BITSIZE) { fputs(one_32, output); fputc(' ', output); fputs(zero_32, output); fputs("\t#sh_addralign\n", output); } else { fputs(one_32, output); fputs("\t#sh_addralign\n", output); } write_register(entry, "sh_entsize"); } char* get_string(int value, int size, int ByteMode, int shift) { char* ch = calloc(42, sizeof(char)); require(NULL != ch, "Exhausted available memory\n"); ch[0] = '\''; stringify(ch+1, size, ByteMode, value, shift); if(!BigEndian) LittleEndian(ch+1, ByteMode); int i = 0; while(0 != ch[i]) { i = i + 1; } ch[i] = '\''; return ch; } char* setup_string(int value, int number_of_bytes, int ByteMode) { int shift; int size; if(HEX == ByteMode) { size = 2; shift = 4; } else if(OCTAL == ByteMode) { size = 3; shift = 3; } else if(BINARY == ByteMode) { size = 8; shift = 1; } else { fputs("reached impossible mode\n", stderr); exit(EXIT_FAILURE); } return get_string(value, number_of_bytes *size, ByteMode, shift); } void setup_strings(int ByteMode) { zero_8 = setup_string(0, 1, ByteMode); zero_16 = setup_string(0, 2, ByteMode); zero_32 = setup_string(0, 4, ByteMode); one_16 = setup_string(1, 2, ByteMode); one_32 = setup_string(1, 4, ByteMode); two_8 = setup_string(2, 1, ByteMode); two_32 = setup_string(2, 4, ByteMode); three_32 = setup_string(3, 4, ByteMode); six_32 = setup_string(6, 4, ByteMode); sixteen_32 = setup_string(16, 4, ByteMode); twentyfour_32 = setup_string(24, 4, ByteMode); } /* Standard C main program */ int main(int argc, char **argv) { jump_table = NULL; struct entry* input = NULL; output = stdout; char* output_file = ""; entry = ""; BITSIZE = 32; count = 1; BigEndian = TRUE; int ByteMode = HEX; int set = FALSE; struct entry* temp; struct entry* head; int option_index = 1; while(option_index <= argc) { if(NULL == argv[option_index]) { option_index = option_index + 1; } else if(match(argv[option_index], "-h") || match(argv[option_index], "--help")) { fputs("Usage: ", stderr); fputs(argv[0], stderr); fputs(" --file FILENAME1 {--file FILENAME2} --output FILENAME\n", stderr); exit(EXIT_SUCCESS); } else if(match(argv[option_index], "--64")) { BITSIZE = 64; option_index = option_index + 1; } else if(match(argv[option_index], "-f") || match(argv[option_index], "--file")) { temp = calloc(1, sizeof(struct entry)); temp->name = argv[option_index + 1]; temp->next = input; input = temp; option_index = option_index + 2; } else if(match(argv[option_index], "-o") || match(argv[option_index], "--output")) { output_file = argv[option_index + 1]; output = fopen(output_file, "w"); if(NULL == output) { fputs("The file: ", stderr); fputs(input->name, stderr); fputs(" can not be opened!\n", stderr); exit(EXIT_FAILURE); } option_index = option_index + 2; } else if(match(argv[option_index], "-b") || match(argv[option_index], "--binary")) { ByteMode = BINARY; option_index = option_index + 1; } else if(match(argv[option_index], "-O") || match(argv[option_index], "--octal")) { ByteMode = OCTAL; option_index = option_index + 1; } else if(match(argv[option_index], "-X") || match(argv[option_index], "--hex")) { ByteMode = HEX; option_index = option_index + 1; } else if(match(argv[option_index], "--big-endian")) { BigEndian = TRUE; set = TRUE; option_index = option_index + 1; } else if(match(argv[option_index], "--little-endian")) { BigEndian = FALSE; set = TRUE; option_index = option_index + 1; } else if(match(argv[option_index], "-V") || match(argv[option_index], "--version")) { fputs("blood-elf 2.0.0\n(Basically Launches Odd Object Dump ExecutabLe Files\n", stdout); exit(EXIT_SUCCESS); } else if(match(argv[option_index], "--entry")) { head = calloc(1, sizeof(struct entry)); /* Include _start or any other entry from your .hex2 */ head->next = jump_table; jump_table = head; jump_table->name = argv[option_index + 1]; /* However only the last one will be exempt from the _name hidden rule */ entry = argv[option_index + 1]; option_index = option_index + 2; count = count + 1; } else { fputs("Unknown option\n", stderr); exit(EXIT_FAILURE); } } /* Make sure we have a program tape to run */ if (NULL == input) { return EXIT_FAILURE; } /* Force setting of endianness */ if(!set) { fputs("either --little-endian or --big-endian MUST be set\n", stderr); return EXIT_FAILURE; } /* Setup the ugly formating because RISC-V sucks */ setup_strings(ByteMode); /* Get all of the labels */ first_pass(input); /* Reverse their order */ jump_table = reverse_list(jump_table); /* Create sections */ /* Create string names for sections */ fputs("# Generated sections\n:ELF_shstr\n", output); fputs(zero_8, output); fputs("\t# NULL\n", output); fputs(":ELF_shstr__text\n\".text\"\n", output); fputs(":ELF_shstr__shstr\n\".shstrtab\"\n", output); fputs(":ELF_shstr__sym\n\".symtab\"\n", output); fputs(":ELF_shstr__str\n\".strtab\"\n", output); /* Create NULL section header as is required by the Spec. So dumb and waste of bytes*/ write_section(":ELF_section_headers", zero_32, zero_32, zero_32, zero_32, zero_32, zero_32, zero_32, zero_32, zero_32); write_section(":ELF_section_header_text", "%ELF_shstr__text>ELF_shstr", one_32, six_32, "&ELF_text", "%ELF_text>ELF_base", "%ELF_data>ELF_text", zero_32, zero_32, zero_32); write_section(":ELF_section_header_shstr", "%ELF_shstr__shstr>ELF_shstr", three_32, zero_32, "&ELF_shstr", "%ELF_shstr>ELF_base", "%ELF_section_headers>ELF_shstr", zero_32, zero_32, zero_32); write_section(":ELF_section_header_str", "%ELF_shstr__str>ELF_shstr", three_32, zero_32, "&ELF_str", "%ELF_str>ELF_base", "%ELF_sym>ELF_str", zero_32, zero_32, zero_32); if(64 == BITSIZE) write_section(":ELF_section_header_sym", "%ELF_shstr__sym>ELF_shstr", two_32, zero_32, "&ELF_sym", "%ELF_sym>ELF_base", "%ELF_end>ELF_sym", three_32, setup_string(count, 4, ByteMode), twentyfour_32); else write_section(":ELF_section_header_sym", "%ELF_shstr__sym>ELF_shstr", two_32, zero_32, "&ELF_sym", "%ELF_sym>ELF_base", "%ELF_end>ELF_sym", three_32, setup_string(count, 4, ByteMode), sixteen_32); /* Create dwarf stubs needed for objdump -d to get function names */ output_string_table(jump_table); output_symbol_table(jump_table); fputs("\n:ELF_end\n", output); /* Close output file */ fclose(output); return EXIT_SUCCESS; } mescc-tools-Release_1.4.0/catm.c000066400000000000000000000032111423361407400164750ustar00rootroot00000000000000/* Copyright (C) 2019 Jeremiah Orians * This file is part of mescc-tools * * mescc-tools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * mescc-tools 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mescc-tools. If not, see . */ #include #include #include #include // CONSTANT BUFFER_SIZE 4096 #define BUFFER_SIZE 4096 int main(int argc, char** argv) { if(2 > argc) { fputs("catm requires 2 or more arguments\n", stderr); exit(EXIT_FAILURE); } int output = open(argv[1], 577 , 384); if(-1 == output) { fputs("The file: ", stderr); fputs(argv[1], stderr); fputs(" is not a valid output file name\n", stderr); exit(EXIT_FAILURE); } int i; int bytes; char* buffer = calloc(BUFFER_SIZE + 1, sizeof(char)); int input; for(i = 2; i < argc ; i = i + 1) { input = open(argv[i], 0, 0); if(-1 == input) { fputs("The file: ", stderr); fputs(argv[i], stderr); fputs(" is not a valid input file name\n", stderr); exit(EXIT_FAILURE); } keep: bytes = read(input, buffer, BUFFER_SIZE); write(output, buffer, bytes); if(BUFFER_SIZE == bytes) goto keep; } free(buffer); return EXIT_SUCCESS; } mescc-tools-Release_1.4.0/check.sh000077500000000000000000000025511423361407400170270ustar00rootroot00000000000000#! /usr/bin/env bash # Copyright © 2017 Jan Nieuwenhuizen # Copyright © 2017 Jeremiah Orians # Copyright (C) 2019 ng0 # # This file is part of mescc-tools # # mescc-tools is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or (at # your option) any later version. # # mescc-tools 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with mescc-tools. If not, see . set -eux [ -e bin ] || mkdir -p bin [ -f bin/M1 ] || exit 1 [ -f bin/hex2 ] || exit 2 [ -f bin/blood-elf ] || exit 3 #[ -f bin/kaem ] || exit 4 [ -f bin/get_machine ] || exit 5 [ -f bin/exec_enable ] || exit 6 [ -e test/results ] || mkdir -p test/results ./test/test0/hello.sh ./test/test1/hello.sh ./test/test2/hello.sh ./test/test3/hello.sh ./test/test4/hello.sh ./test/test5/hello.sh ./test/test6/hello.sh ./test/test7/hello.sh ./test/test8/hello.sh ./test/test9/hello.sh ./test/test10/hello.sh ./test/test11/hello.sh . sha256.sh sha256_check test/test.answers mescc-tools-Release_1.4.0/docs/000077500000000000000000000000001423361407400163405ustar00rootroot00000000000000mescc-tools-Release_1.4.0/docs/M1.1000066400000000000000000000042111423361407400166750ustar00rootroot00000000000000.\"Made with Love .TH M1 1 "JULY 2019" Linux "User Manuals" .SH NAME M1 \- The universal Macro assembler .SH SYNOPSIS .na M1 --architecture ARCHITECTURE --file FILE [--output FILE --octal --binary --big-endian --little-endian] .SH DESCRIPTION M1 is the most minimal cross-platform macro assembler possible .br Leveraging a few grammar details to provide the user with a rich vocabulary of ways of expressing their desired output and input; thus eliminating surprise from the generation process. .br At it's core is DEFINE MACRO EXPANDED .br Where one can define an assembly instruction like: DEFINE INT_80 CD80 and know that everywhere INT_80 is placed in the input file there will be the hex encoding of that instruction in the output file or if no output file is specified the output will be send to standard out. .br The supported ARCHITECTURES are as follows: knight-native, knight-posix, x86, amd64, armv7l and aarch64. If you fail to specify an architecture, the default of knight-native will be used. .br M1 also supports the generation of 8, 16 and 32bit integers provided they are encoded as !NUM, @NUM or %NUM respectively. eg !-1, @42 and %8675309 You however can not mix integers with definitions as macros are always applied first and will not be evaluated further. Should you wish to specify the bit and byte encoding of the integers to match your target --big-endian and --little-endian Should you wish for the output to be something other than hex format, you can specify the exact output you desire with: --octal or --binary .SH EXAMPLES Typically, M1 will be called in scripts used in bootstrapping .br # M1 -f x86.defs -f libc-core.M1 -f cc.M1 -f cc-footer.M1 --little-endian --architecture x86 -o cc.hex2 .br .SH COMPATIBILITY M1 is compatible with all Turing complete machines; even the ones that try to be Turing complete -1 .SH AUTHORS Jeremiah Orians .br Jan (janneke) Nieuwenhuizen .SH COPYRIGHT Copyright 2016-2019 Jeremiah Orians .br Copyright 2017 Jan Nieuwenhuizen .br License GPLv3+. .SH "SEE ALSO" hex2(1), blood-elf(1), kaem(1), syscalls(2) mescc-tools-Release_1.4.0/docs/blood-elf.1000066400000000000000000000025461423361407400202740ustar00rootroot00000000000000.\"Made with Love .TH blood-elf 1 "JULY 2019" Linux "User Manuals" .SH NAME blood-elf - Get mescc with dwarfs .SH SYNOPSIS .na blood-elf --file FILE [--output FILE --64] .SH DESCRIPTION blood-elf exists to generate ELF debug tables in M1-macro format from M1-macro assembly files. .br At its core is read until you find :LABEL and then add it to the list of things to output. It will ignore labels that have '_' prefixing their name. eg :_foo will not get an entry. If no output is specified, the result will be sent to Standard Out. .br Fortunately the only architecture difference that you need to concern yourself with is if your binary is going to be 64bits or 32bits (which is the default) and to pass the flag: --64 should you need that alternate format .SH EXAMPLES Typically, blood-elf will be called in scripts used in bootstrapping .br # blood-elf -f cc.M1 -o cc-footer.M1 .br # blood-elf --file cc.M1 --64 --output cc-footer.M1 .br .SH COMPATIBILITY blood-elf is compatible with all Turing complete machines; even the ones that try to be Turing complete -1. .SH AUTHORS Jeremiah Orians .br Jan (janneke) Nieuwenhuizen .SH COPYRIGHT Copyright 2016-2019 Jeremiah Orians .br Copyright 2017 Jan Nieuwenhuizen .br License GPLv3+. .SH "SEE ALSO" M1(1), hex2(1), kaem(1), syscalls(2) mescc-tools-Release_1.4.0/docs/get_machine.1000066400000000000000000000033711423361407400206710ustar00rootroot00000000000000.\"Made with Love .TH get_machine 1 "JULY 2019" Linux "User Manuals" .SH NAME get_machine - identify running hardware architecture .SH SYNOPSIS .na get_machine [ --exact --override OVERRIDE --os ] .SH DESCRIPTION get_machine exists to make simple shell scripts that need to know that hardware architecture it is assuming or what host operating system is being used. .br At its core is figure out the general hardware architecture and return it as quickly as possible. Although it is sometimes useful to return something different; which is why --override exists and thus what ever is supplied by with it is returned. Scripts that wish to expose that can leverage the environment variable GET_MACHINE_FLAGS to allow efficient overriding in their scripts. Or if they wish to only override what Operating system is running the environment variable GET_MACHINE_OS_FLAGS should be used. .br If one wishes for something more exact than x86 or amd64, the option --exact will return more specific values like i686-pae. .br Should one desire to know the host operating system: --os .br A word of warning; --override always will take top precedence and can return anything you desire. .SH EXAMPLES Typically, get_machine will be in scripts used in bootstrapping .br # get_machine .br # get_machine --override "I am the very model of a modern major general" .br # get_machine ${GET_MACHINE_FLAGS} .br # get_machine ${GET_MACHINE_OS_FLAGS} --os .br .SH COMPATIBILITY get_machine is compatible with all Turing complete machines; even the ones that try to be Turing complete -1 .SH AUTHORS Jeremiah Orians .SH COPYRIGHT Copyright 2016-2021 Jeremiah Orians .br License GPLv3+. .SH "SEE ALSO" M1(1), hex2(1), blood-elf(1), kaem(1), syscalls(2) mescc-tools-Release_1.4.0/docs/hex2.1000066400000000000000000000047311423361407400172750ustar00rootroot00000000000000.\"Made with Love .TH hex2 1 "JULY 2019" Linux "User Manuals" .SH NAME hex2 - The trivially bootstrappable linker that is designed to be introspectable by humans .SH SYNOPSIS .na hex2 --architecture ARCHITECTURE --base-address ADDRESS --file FILE [--output FILE [--non-executable]] .SH DESCRIPTION hex2 is designed to allow humans to write elf and other binary files by hand in a format that allows comments and ease of understanding. .br At its core is read 2 hex characters add them together and output a single byte. You can override this and use binary or octal input if you so desire, using the --octal or --binary option. .br If no output file is specified the output will be send to standard out. By default the file will be executable unless the option: --non-executable is also passed. .br The supported ARCHITECTURES are as follows: knight-native, knight-posix, x86, amd64, armv7l and aarch64. If you fail to specify an architecture, the default of knight-native will be used. .br The base address for which the binary is to be loaded into memory and thus the relative and absolute pointers should be based, is passed via --base-address if it is not provided the default value of ZERO will be assumed. .br hex2 also support labels in the :LABEL format and relative and absolute pointers to those labels in 8, 16, 24 or 32bit sizes. !LABEL, @LABEL, ~LABEL and %LABEL for 8, 16, 24 and 32bit relative addresses respectively and $LABEL and &LABEL for 16 and 32bit absolute addresses respectively. Should you wish to specify the bit and byte encoding of the addresses to match your target --big-endian and --little-endian On architectures that require word alignment the < and ^ characters have a special meaning; particularly pad to word and use word base address calculation rather than standard byte based address calculation; generally seen in the form: ^~LABEL EB for calls in ARM .SH EXAMPLES Typically, hex2 will be called in scripts used in bootstrapping .br # hex2 -f ELF-armv7l.hex2 -f cc.hex2 --little-endian --architecture armv7l --base-address 0x10000 -o cc .br .SH COMPATIBILITY hex2 is compatible with all Turing complete machines; even the ones that try to be Turing complete -1 .SH AUTHORS Jeremiah Orians .br Jan (janneke) Nieuwenhuizen .SH COPYRIGHT Copyright 2016-2019 Jeremiah Orians .br Copyright 2017 Jan Nieuwenhuizen .br License GPLv3+. .SH "SEE ALSO" M1(1), blood-elf(1), kaem(1), syscalls(2) mescc-tools-Release_1.4.0/docs/kaem.1000066400000000000000000000032011423361407400173330ustar00rootroot00000000000000.\"Made with Love .TH kaem 1 "JULY 2019" Linux "User Manuals" .SH NAME kaem - Like running with scissors but shell scripts without a shell .SH SYNOPSIS .na kaem [--file FILE --strict --verbose --nightmare-mode] .SH DESCRIPTION kaem exists to be the most minimal shell needed in the bootstrap processes; that has the ability to function as an init thus allowing the bootstrap to occur with only itself and a hex0 assembler as the only binaries running on the system. .br At its core is read a line (except when the line is terminated with a '\\', when it is read the next line too) and then collect the arguments into an array, lookup the program in the path provided by the name or if not found in the ENVIRONMENT and then execute the program with the specified options. .br If no filename is passed, it then attempts to execute a file called kaem.run; which is the standard name for kaem scripts. If you wish for kaem to stop when one of the lines throws or returns an error code, simply add --strict. If you wish to see what is being executed, simply add --verbose. If you hate dealing with an environment and want to eliminate it entirely --nightmare-mode. .SH EXAMPLES Typically, kaem will be in running scripts used in bootstrapping .br # kaem --verbose --strict .br # kaem -f bootstrap.sh --nightmare-mode .br .SH COMPATIBILITY kaem is compatible with all Turing complete machines; even the ones that try to be Turing complete -1 .SH AUTHORS Jeremiah Orians .SH COPYRIGHT Copyright 2016-2019 Jeremiah Orians .br License GPLv3+. .SH "SEE ALSO" M1(1), hex2(1), blood-elf(1), get_machine(1), syscalls(2) mescc-tools-Release_1.4.0/elf_headers/000077500000000000000000000000001423361407400176515ustar00rootroot00000000000000mescc-tools-Release_1.4.0/elf_headers/elf32-ARM-debug.hex2000066400000000000000000000057131423361407400230630ustar00rootroot00000000000000### Copyright (C) 2016 Jeremiah Orians ### Copyright (C) 2017 Jan Nieuwenhuizen ### This file is part of stage0. ### ### stage0 is free software: you can redistribute it and/or modify ### it under the terms of the GNU General Public License as published by ### the Free Software Foundation, either version 3 of the License, or ### (at your option) any later version. ### ### stage0 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 General Public License for more details. ### ### You should have received a copy of the GNU General Public License ### along with stage0. If not, see . ### stage0's hex2 format ### !