├── .gitignore ├── CONTRIBUTING ├── LICENSE ├── Makefile ├── README ├── bin2h.c ├── elfling.cpp ├── flow2.c ├── header.asm ├── header64.asm ├── pack.cpp ├── pack.h ├── packer.cpp ├── prt.c └── unpack.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | bin 3 | header32.h 4 | header64.h 5 | test 6 | core 7 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at the end). 2 | 3 | ### Before you contribute 4 | Before we can use your code, you must sign the 5 | [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) 6 | (CLA), which you can do online. The CLA is necessary mainly because you own the 7 | copyright to your changes, even after your contribution becomes part of our 8 | codebase, so we need your permission to use and distribute your code. We also 9 | need to be sure of various other things—for instance that you'll tell us if you 10 | know that your code infringes on other people's patents. You don't have to sign 11 | the CLA until after you've submitted your code for review and a member has 12 | approved it, but you must do it before we can put your code into our codebase. 13 | Before you start working on a larger contribution, you should get in touch with 14 | us first through the issue tracker with your idea so that we can help out and 15 | possibly guide you. Coordinating up front makes it much easier to avoid 16 | frustration later on. 17 | 18 | ### Code reviews 19 | All submissions, including submissions by project members, require review. We 20 | use Github pull requests for this purpose. 21 | 22 | ### The small print 23 | Contributions made by corporations are covered by a different agreement than 24 | the one above, the Software Grant and Corporate Contributor License Agreement. 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: bin/prt bin/prt2 2 | 3 | bin: 4 | mkdir bin 5 | 6 | bin/bin2h: bin bin2h.c 7 | gcc -std=c99 bin2h.c -o bin/bin2h 8 | 9 | header32.h: header.asm bin/bin2h 10 | nasm header.asm -f bin -o bin/header32.bin 11 | bin/bin2h bin/header32.bin header32.h header32 12 | ls -al bin/header32.bin 13 | 14 | header64.h: header64.asm bin/bin2h 15 | nasm header64.asm -f bin -o bin/header64.bin 16 | bin/bin2h bin/header64.bin header64.h header64 17 | ls -al bin/header64.bin 18 | 19 | bin/elfling: elfling.cpp header32.h header64.h pack.cpp unpack.cpp pack.h 20 | gcc -std=c++11 -O3 -g pack.cpp -c -o bin/pack.o 21 | gcc -std=c++11 -O3 -g unpack.cpp -c -o bin/unpack.o 22 | g++ -std=c++11 -g elfling.cpp bin/pack.o bin/unpack.o -o bin/elfling 23 | 24 | bin/crunkler_2: crunkler_2.cpp 25 | g++ -std=c++11 -g crunkler_2.cpp -o bin/crunkler_2 26 | 27 | bin/prt.o: prt.c bin 28 | gcc -Os -c prt.c -fomit-frame-pointer -fno-exceptions -o bin/prt.o -m32 29 | 30 | bin/prt: bin/prt.o 31 | gcc bin/prt.o -s -nostartfiles -o bin/prt -m32 32 | 33 | bin/prt2: bin/prt.o bin/elfling 34 | bin/elfling bin/prt.o -obin/prt2 -llibc.so.6 #-fnosh 35 | chmod 755 bin/prt2 36 | 37 | bin/prt_64.o: prt.c bin 38 | gcc -Os -c prt.c -fomit-frame-pointer -fno-exceptions -o bin/prt_64.o 39 | 40 | bin/prt_64: bin/prt_64.o 41 | gcc bin/prt_64.o -s -nostartfiles -o bin/prt_64 42 | 43 | bin/prt2_64: bin/prt_64.o bin/elfling 44 | bin/elfling bin/prt_64.o -obin/prt2_64 -llibc.so.6 #-fnosh 45 | chmod 755 bin/prt2_64 46 | 47 | bin/flow2: flow2.c bin/elfling 48 | gcc -Os -c flow2.c -fomit-frame-pointer -fno-exceptions -ffast-math -fsingle-precision-constant -o bin/flow2.o -m32 49 | bin/elfling bin/flow2.o -obin/flow2 -llibSDL-1.2.so.0 -llibGL.so.1 -c0801010205070b0b0734273ac30403158d 50 | chmod 755 bin/flow2 51 | 52 | bin/flow2_64: flow2.c bin/elfling 53 | gcc -Os -c flow2.c -fomit-frame-pointer -fno-exceptions -ffast-math -fsingle-precision-constant -o bin/flow2_64.o 54 | bin/elfling bin/flow2_64.o -obin/flow2_64 -llibSDL-1.2.so.0 -llibGL.so.1 -c080101020503070bc303c9361704030a2b 55 | chmod 755 bin/flow2_64 56 | 57 | bin/flow_64: flow2.c 58 | gcc -Os -c flow2.c -fomit-frame-pointer -fno-exceptions -ffast-math -fsingle-precision-constant -o bin/flow2_64.o 59 | gcc bin/flow2_64.o -s -nostartfiles -o bin/flow_64 -lGL -lSDL 60 | 61 | bin/packer: packer.cpp unpack.cpp pack.cpp pack.h 62 | g++ -std=c++11 -g packer.cpp -c -o bin/packer.o -m32 63 | gcc -std=c++11 -g unpack.cpp -c -o bin/unpack.o -m32 64 | gcc -std=c++11 -O3 -g pack.cpp -c -o bin/pack.o -m32 65 | g++ -std=c++11 -g bin/packer.o bin/pack.o bin/unpack.o -o bin/packer -m32 66 | 67 | packtest: bin/packer bin/prt 68 | bin/packer bin/prt 69 | bin/packer bin/prt.pack 70 | diff bin/prt bin/prt.unpack 71 | 72 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Elfling by Minas ^ Calodox 2 | 3 | This is an attempt at writing something Crinkler-like for the Linux Scene. It 4 | provides a context-modeling compressing linker that will transform a .o file 5 | into a "valid" ELF binary. This is not quite finished yet, the following 6 | caveats should be taken into account when using: 7 | - It can only link a single .o file for now. 8 | - It assumes that you want to link SDL 1.2 and OpenGL, the flags for specifying 9 | libraries are currently ignored. 10 | - It may crash if your object file contains some construct it does not expect. 11 | While I have tested quite a few relocation and data declaration possibilities 12 | I am absolutely certain to have missed a few :-) 13 | - 32-bit only. While the resulting binaries will run on 64-bit Linux, users will 14 | need to install the required 32-bit libraries for running your stuff. 15 | 16 | Have fun :-) Improvements welcome, this is open source after all! 17 | 18 | This is not an official Google product. 19 | -------------------------------------------------------------------------------- /bin2h.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | #include 18 | 19 | int main(int argc, char* argv[]) { 20 | if (argc < 4) { printf("Usage: bin2h [in] [out] [var]\n"); return 1; } 21 | FILE* fptr = fopen(argv[1], "rb"); 22 | if (fptr == NULL) { printf("Could not open %s\n", argv[1]); return 1; } 23 | unsigned char buf[4096]; 24 | int l = fread(buf, 1, 4096, fptr); 25 | fclose(fptr); 26 | if (l <= 0) { printf("%s is empty\n", argv[1]); return 1; } 27 | fptr = fopen(argv[2], "w"); 28 | if (fptr == NULL) { printf("Could not open %s\n", argv[2]); return 1; } 29 | fprintf(fptr, "unsigned char %s[] = {", argv[3]); 30 | for (int i = 0; i < l; ++i) { 31 | if ((i & 15) == 0) { fprintf(fptr, "\n "); } 32 | fprintf(fptr, "0x%2.2x, ", buf[i]); 33 | } 34 | fprintf(fptr, "\n};\n"); 35 | fclose(fptr); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /elfling.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "header32.h" 28 | #include "header64.h" 29 | #include "pack.h" 30 | 31 | bool verbose = false; 32 | 33 | typedef unsigned char u8; 34 | typedef unsigned int u32; 35 | typedef unsigned long long u64; 36 | 37 | template struct Elf { 38 | }; 39 | template<> struct Elf<32> { 40 | typedef Elf32_Shdr Shdr; 41 | typedef Elf32_Phdr Phdr; 42 | typedef Elf32_Ehdr Ehdr; 43 | typedef Elf32_Sym Sym; 44 | typedef Elf32_Rel Rel; 45 | typedef Elf32_Rela Rela; 46 | }; 47 | template<> struct Elf<64> { 48 | typedef Elf64_Shdr Shdr; 49 | typedef Elf64_Phdr Phdr; 50 | typedef Elf64_Ehdr Ehdr; 51 | typedef Elf64_Sym Sym; 52 | typedef Elf64_Rel Rel; 53 | typedef Elf64_Rela Rela; 54 | }; 55 | 56 | template class Section { 57 | typedef Elf E; 58 | public: 59 | Section(const char* name) : name_(name) {} 60 | ~Section() { 61 | delete[] data_; 62 | } 63 | 64 | void Set(const void* data, u32 size) { 65 | if (size > limit_) { 66 | delete[] data_; 67 | data_ = new u8[size]; 68 | limit_ = size; 69 | } 70 | memcpy(data_, data, size); 71 | size_ = size; 72 | } 73 | void Reset() { 74 | size_ = 0; 75 | } 76 | void Append(const void* data, u32 size) { 77 | if (size + size_ > limit_) { 78 | limit_ = (size + size_ + 0x0fff) & (~0x0fff); 79 | u8* nd = new u8[limit_]; 80 | memcpy(nd, data_, size_); 81 | delete[] data_; 82 | data_ = nd; 83 | } 84 | memcpy(&data_[size_], data, size); 85 | size_ += size; 86 | } 87 | void SetHdr(const typename E::Shdr& hdr) { 88 | hdr_ = hdr; 89 | } 90 | const typename E::Shdr& Hdr() const { return hdr_; } 91 | 92 | const std::string& Name() const { return name_; } 93 | const u8* Data() const { return data_; } 94 | u32 Size() const { return size_; } 95 | 96 | protected: 97 | std::string name_; 98 | u32 size_ = 0; 99 | u32 limit_ = 0; 100 | u8* data_ = nullptr; 101 | 102 | typename E::Shdr hdr_; 103 | }; 104 | 105 | class MemFile { 106 | public: 107 | MemFile() {} 108 | ~MemFile() { 109 | delete[] data_; 110 | } 111 | bool Load(const char* fn) { 112 | name_ = fn; 113 | FILE* fptr = fopen(fn, "rb"); 114 | if (!fptr) { 115 | printf("Could not open %s\n", fn); 116 | return false; 117 | } 118 | fseek(fptr, 0, SEEK_END); 119 | size_ = ftell(fptr); 120 | fseek(fptr, 0, 0); 121 | data_ = new u8[size_]; 122 | u32 rl = fread(data_, 1, size_, fptr); 123 | if (size_ != rl) { 124 | printf("Could not read %s\n", fn); 125 | return false; 126 | } 127 | fclose(fptr); 128 | return true; 129 | } 130 | 131 | const char* Name() const { return name_.c_str(); } 132 | const u8* Data() const { return data_; } 133 | size_t Size() const { return size_; } 134 | 135 | private: 136 | u8* data_ = nullptr; 137 | size_t size_ = 0; 138 | std::string name_; 139 | }; 140 | 141 | template class Image { 142 | typedef Elf E; 143 | public: 144 | Image() {} 145 | ~Image() { 146 | for (Section* s : sections_) { 147 | delete s; 148 | } 149 | } 150 | 151 | bool Load(MemFile* f) { 152 | const u8* obj = f->Data(); 153 | u8 elfMagic[4] = {0x7f, 0x45, 0x4c, 0x46}; 154 | memcpy(&ehdr_, obj, sizeof(ehdr_)); 155 | if (memcmp(ehdr_.e_ident, elfMagic, 4)) { 156 | printf("Invalid header signature in %s\n", f->Name()); 157 | return false; 158 | } 159 | if (ehdr_.e_phnum) { 160 | if (ehdr_.e_phentsize != sizeof(typename E::Phdr)) { 161 | printf("Object %s has unexpected e_phentsize (%d != %lu)\n", f->Name(), ehdr_.e_phentsize, sizeof(typename E::Phdr)); 162 | return false; 163 | } 164 | memcpy(phdr_, &obj[ehdr_.e_phoff], ehdr_.e_phnum * ehdr_.e_phentsize); 165 | } 166 | if (ehdr_.e_shentsize != sizeof(typename E::Shdr)) { 167 | printf("Object %s has unexpected e_shentsize (%d != %lu)\n", f->Name(), ehdr_.e_shentsize, sizeof(typename E::Shdr)); 168 | return false; 169 | } 170 | memcpy(shdr_, &obj[ehdr_.e_shoff], ehdr_.e_shnum * ehdr_.e_shentsize); 171 | 172 | // Get the strings for now 173 | char* strings = (char*)&obj[shdr_[ehdr_.e_shstrndx].sh_offset]; 174 | for (u32 i = 0; i < ehdr_.e_shnum; ++i) { 175 | if (verbose) 176 | printf("Loading section '%s' at offset 0x%x, %d bytes\n", &strings[shdr_[i].sh_name], (u32)shdr_[i].sh_offset, (int)shdr_[i].sh_size); 177 | Section* s = new Section(&strings[shdr_[i].sh_name]); 178 | if (shdr_[i].sh_type != SHT_NOBITS) { 179 | s->Set(&obj[shdr_[i].sh_offset], shdr_[i].sh_size); 180 | } 181 | s->SetHdr(shdr_[i]); 182 | sectionMap_[s->Name()] = s; 183 | sections_.push_back(s); 184 | } 185 | return true; 186 | } 187 | 188 | u32 SectionCount() const { return sections_.size(); } 189 | Section* GetSection(const char* str) { 190 | typename std::map*>::iterator it = sectionMap_.find(str); 191 | if (it == sectionMap_.end()) { return nullptr; } 192 | return it->second; 193 | } 194 | Section* GetSection(u32 s) { 195 | if (s < sections_.size()) { return sections_[s]; } 196 | return nullptr; 197 | } 198 | private: 199 | typename E::Ehdr ehdr_; 200 | typename E::Phdr phdr_[64]; 201 | typename E::Shdr shdr_[256]; 202 | 203 | std::map*> sectionMap_; 204 | std::vector*> sections_; 205 | }; 206 | 207 | const u32 base = 0x08000000; 208 | 209 | u32 rol(u32 v, u32 s) { 210 | return (v << s) | ( v >> (32 - s)); 211 | } 212 | 213 | u32 hash(const char* str) { 214 | u32 rv = 0; 215 | for (const char* a = str; *a; ++a) { 216 | rv ^= *a; 217 | rv = rol(rv, 5); 218 | } 219 | rv = rol(rv, 5); 220 | return rv; 221 | } 222 | 223 | std::map> args; 224 | 225 | bool HasFlag(const char* flag) { 226 | return args['f'].find(flag) != args['f'].end(); 227 | } 228 | 229 | const char* FlagWithDefault(char f, const char* def) { 230 | if (args[f].size() > 0) { 231 | return args[f].begin()->c_str(); 232 | } else { 233 | return def; 234 | } 235 | } 236 | 237 | void Invert(u8* data, u32 s) { 238 | for (u32 i = 0; i < s >> 1; ++i) { 239 | u8 t = data[i]; 240 | data[i] = data[s - i - 1]; 241 | data[s - i - 1] = t; 242 | } 243 | } 244 | 245 | template class Linker { 246 | typedef typename Elf::Sym Sym; 247 | typedef typename Elf::Rel Rel; 248 | typedef typename Elf::Rela Rela; 249 | public: 250 | bool Link(MemFile* o) { 251 | Image obj; 252 | if (!obj.Load(o)) { 253 | return false; 254 | } 255 | 256 | // Start off by finding the _start symbol. 257 | Section* symtab = obj.GetSection(".symtab"); 258 | Sym* symbols = (Sym*)symtab->Data(); 259 | char* symbolNames = (char*)obj.GetSection(symtab->Hdr().sh_link)->Data(); 260 | u32 startSection = 0; 261 | u32 startOffset = 0; 262 | { 263 | u32 sc = symtab->Size() / sizeof(Sym); 264 | for (u32 i = 0; i < sc; ++i) { 265 | // The ELF32_ST_XXX macros are identical to ELF64_ST_XXX. 266 | if (!strcmp(&symbolNames[symbols[i].st_name], "_start")) { 267 | startSection = symbols[i].st_shndx; 268 | startOffset = symbols[i].st_value; 269 | } 270 | } 271 | } 272 | 273 | std::set imports; 274 | std::map sections; 275 | std::map common; 276 | u32 commonOff = 0; 277 | Section* bss = obj.GetSection(".bss"); 278 | sections[".text"] = 0; 279 | if (bss) { 280 | commonOff += bss->Size(); 281 | } 282 | 283 | for (u32 i = 0; i < obj.SectionCount(); ++i) { 284 | if (!strncmp(obj.GetSection(i)->Name().c_str(), ".rel.", 5) && bits == 32) { 285 | if (bits != 32) { printf("Unsupported relocation: .rel with 64 bits\n"); return false; } 286 | Section* rel = obj.GetSection(i); 287 | Rel* tr = (Rel*)rel->Data(); 288 | for (u32 j = 0; j < rel->Size() / sizeof(Rel); ++j) { 289 | u32 sym = ELF32_R_SYM(tr[j].r_info); 290 | u32 type = ELF32_R_TYPE(tr[j].r_info); 291 | if (symbols[sym].st_shndx && symbols[sym].st_shndx < obj.SectionCount()) { 292 | if (obj.GetSection(symbols[sym].st_shndx)->Name() != ".bss") { 293 | sections[obj.GetSection(symbols[sym].st_shndx)->Name()] = 0; 294 | } 295 | } 296 | if (ELF32_ST_TYPE(symbols[sym].st_info) == STT_NOTYPE && ELF32_ST_BIND(symbols[sym].st_info) == STB_GLOBAL) { 297 | imports.insert(&symbolNames[symbols[sym].st_name]); 298 | } 299 | if (symbols[sym].st_shndx == SHN_COMMON && common.find(symbols[sym].st_name) == common.end()) { 300 | common[symbols[sym].st_name] = commonOff; 301 | commonOff += symbols[sym].st_size; 302 | } 303 | } 304 | } else if (!strncmp(obj.GetSection(i)->Name().c_str(), ".rela.", 6)) { 305 | if (bits != 64) { printf("Unsupported relocation: .rela with 32 bits\n"); return false; } 306 | Section* rel = obj.GetSection(i); 307 | Rela* tr = (Rela*)rel->Data(); 308 | for (u32 j = 0; j < rel->Size() / sizeof(Rela); ++j) { 309 | u32 sym = ELF64_R_SYM(tr[j].r_info); 310 | u32 type = ELF64_R_TYPE(tr[j].r_info); 311 | if (symbols[sym].st_shndx && symbols[sym].st_shndx < obj.SectionCount()) { 312 | if (obj.GetSection(symbols[sym].st_shndx)->Name() != ".bss") { 313 | sections[obj.GetSection(symbols[sym].st_shndx)->Name()] = 0; 314 | } 315 | } 316 | if (ELF32_ST_TYPE(symbols[sym].st_info) == STT_NOTYPE && ELF32_ST_BIND(symbols[sym].st_info) == STB_GLOBAL) { 317 | imports.insert(&symbolNames[symbols[sym].st_name]); 318 | } 319 | if (symbols[sym].st_shndx == SHN_COMMON && common.find(symbols[sym].st_name) == common.end()) { 320 | common[symbols[sym].st_name] = commonOff; 321 | commonOff += symbols[sym].st_size; 322 | } 323 | } 324 | } 325 | } 326 | 327 | const char* sig = "XXXX-Compressed code here-XXXX"; 328 | u32 sz = 0; 329 | for (const u8* compoff = Header(); compoff < Header() + HeaderSize() - strlen(sig); ++compoff) { 330 | if (!memcmp(compoff, sig, strlen(sig))) { 331 | sz = compoff - Header(); 332 | break; 333 | } 334 | } 335 | 336 | u8* finalout = (u8*)malloc(65536); 337 | u32 finalsize = HeaderSize() - strlen(sig) - sz; 338 | memcpy(finalout, &Header()[sz + strlen(sig)], finalsize); 339 | u32 tailoff = finalsize; 340 | 341 | u32 hashoff = finalsize; 342 | for (const std::string& imp : imports) { 343 | if (verbose) 344 | printf("Import %-15s @ 0x%8.8x\n", imp.c_str(), finalsize); 345 | if (bits == 32) { 346 | // 5 byte jump table entries: 347 | // e9 xx xx xx xx jmp dword relative 348 | finalout[finalsize++] = 0xe9; 349 | *(u32*)&finalout[finalsize] = hash(imp.c_str()); 350 | finalsize += 4; 351 | } else { 352 | // 14 byte jump table entries: 353 | // ff 25 00 00 00 00 jmp [rip + rel] 354 | // xx xx xx xx xx xx xx xx absolute destination of jump 355 | finalout[finalsize++] = 0xff; 356 | finalout[finalsize++] = 0x25; 357 | *(u32*)&finalout[finalsize] = 0; 358 | finalsize += 4; 359 | *(u64*)&finalout[finalsize] = hash(imp.c_str()); 360 | finalsize += 8; 361 | } 362 | } 363 | // Add one more entry with all zeroes for termination. 364 | for (int i = 0; i < (bits == 32 ? 5 : 14); ++i) { 365 | finalout[finalsize++] = 0; 366 | } 367 | // Put in entry point as relative 32-bit address. The assembly header ends 368 | // with a relative jump. 369 | *(u32*)&finalout[tailoff - 4] = finalsize + startOffset - tailoff; 370 | 371 | // We now have a list of all referenced sections, locate them in the final 372 | // binary. 373 | u32 textoff = 0; 374 | for (auto& sec : sections) { 375 | // Take all sections starting with ".text" 376 | if (!strncmp(sec.first.c_str(), ".text", 5)) { 377 | sec.second = finalsize; 378 | textoff = finalsize; 379 | printf("Section %-15s @ 0x%8.8x\n", sec.first.c_str(), finalsize); 380 | finalsize += obj.GetSection(sec.first.c_str())->Size(); 381 | } 382 | } 383 | for (auto& sec : sections) { 384 | // Take all sections not starting with ".text" 385 | if (strncmp(sec.first.c_str(), ".text", 5)) { 386 | sec.second = finalsize; 387 | printf("Section %-15s @ 0x%8.8x\n", sec.first.c_str(), finalsize); 388 | finalsize += obj.GetSection(sec.first.c_str())->Size(); 389 | } 390 | } 391 | for (auto& sec : sections) { 392 | // Copy section contents. 393 | memcpy(&finalout[sec.second], obj.GetSection(sec.first.c_str())->Data(), obj.GetSection(sec.first.c_str())->Size()); 394 | } 395 | 396 | u32 commonbase = (finalsize + 255) & (~255); 397 | if (bss) { 398 | sections[".bss"] = commonbase; 399 | printf("Section .bss @ 0x%8.8x\n", commonbase); 400 | commonbase += bss->Size(); 401 | } 402 | 403 | // Apply text relocations. 404 | for (u32 i = 0; i < obj.SectionCount(); ++i) { 405 | if (!strncmp(obj.GetSection(i)->Name().c_str(), ".rel.", 5)) { 406 | const char* secName = obj.GetSection(i)->Name().c_str() + 4; 407 | if (sections.find(secName) == sections.end()) continue; 408 | if (verbose) 409 | printf("Relocating %s\n", secName); 410 | Section* rel = obj.GetSection(i); 411 | Rel* tr = (Rel*)rel->Data(); 412 | u32 trc = rel->Size() / sizeof(Rel); 413 | Sym* st = (Sym*)obj.GetSection(rel->Hdr().sh_link)->Data(); 414 | char* sn = (char*)obj.GetSection(obj.GetSection(rel->Hdr().sh_link)->Hdr().sh_link)->Data(); 415 | u32 secoff = sections[secName]; 416 | for (u32 j = 0; j < trc; ++j) { 417 | u32 sym, type; 418 | sym = ELF32_R_SYM(tr[j].r_info); 419 | type = ELF32_R_TYPE(tr[j].r_info); 420 | u32* off = (u32*)&finalout[secoff + tr[j].r_offset]; 421 | u32 b = 0; 422 | const char* bind = "*"; 423 | switch (ELF32_ST_BIND(symbols[sym].st_info)) { 424 | case STB_LOCAL: bind = "STB_LOCAL"; break; 425 | case STB_GLOBAL: bind = "STB_GLOBAL"; break; 426 | case STB_WEAK: bind = "STB_WEAK"; break; 427 | } 428 | const char* types = "*"; 429 | switch (ELF32_ST_TYPE(symbols[sym].st_info)) { 430 | case STT_NOTYPE: types = "STT_NOTYPE"; break; 431 | case STT_OBJECT: types = "STT_OBJECT"; break; 432 | case STT_FUNC: types = "STT_FUNC"; break; 433 | case STT_SECTION: types = "STT_SECTION"; break; 434 | case STT_FILE: types = "STT_FILE"; break; 435 | } 436 | if (verbose) 437 | printf(" %3d %4x %2d %3d %-20s %-10s %-10s %4x %4x %x %-s %x\n", 438 | j, (u32)tr[j].r_offset, type, sym, &symbolNames[symbols[sym].st_name], 439 | bind, types, (u32)symbols[sym].st_value, (u32)symbols[sym].st_size, 440 | symbols[sym].st_other, symbols[sym].st_shndx < obj.SectionCount() ? obj.GetSection(symbols[sym].st_shndx)->Name().c_str() : "*", 441 | symbols[sym].st_shndx); 442 | u32 sec = st[sym].st_shndx; 443 | if (sec && sec < obj.SectionCount()) { 444 | b = base + sections[obj.GetSection(st[sym].st_shndx)->Name()] + symbols[sym].st_value; 445 | } else if (sec == SHN_COMMON) { 446 | b = base + commonbase + common[st[sym].st_name]; 447 | } else if (sec == 0) { 448 | u32 func = 0; 449 | for (const std::string& imp : imports) { 450 | if (imp == &symbolNames[symbols[sym].st_name]) break; 451 | ++func; 452 | } 453 | b = hashoff + 5 * func + base; 454 | } else { 455 | printf("Unknown section %x\n", sec); 456 | } 457 | if (type == R_386_32) { 458 | *off += b + 0x10000; 459 | } else if (type == R_386_PC32) { 460 | *off += b - tr[j].r_offset - secoff - base; 461 | } else { 462 | printf("Unknown type %d\n", type); 463 | } 464 | } 465 | } else if (!strncmp(obj.GetSection(i)->Name().c_str(), ".rela.", 6)) { 466 | const char* secName = obj.GetSection(i)->Name().c_str() + 5; 467 | if (sections.find(secName) == sections.end()) continue; 468 | if (verbose) 469 | printf("Relocating %s\n", secName); 470 | Section* rel = obj.GetSection(i); 471 | Rela* tr = (Rela*)rel->Data(); 472 | u32 trc = rel->Size() / sizeof(Rela); 473 | Sym* st = (Sym*)obj.GetSection(rel->Hdr().sh_link)->Data(); 474 | char* sn = (char*)obj.GetSection(obj.GetSection(rel->Hdr().sh_link)->Hdr().sh_link)->Data(); 475 | u32 secoff = sections[secName]; 476 | for (u32 j = 0; j < trc; ++j) { 477 | u32 sym, type; 478 | sym = ELF64_R_SYM(tr[j].r_info); 479 | type = ELF64_R_TYPE(tr[j].r_info); 480 | u32* off = (u32*)&finalout[secoff + tr[j].r_offset]; 481 | u32 b = 0; 482 | const char* bind = "*"; 483 | switch (ELF32_ST_BIND(symbols[sym].st_info)) { 484 | case STB_LOCAL: bind = "STB_LOCAL"; break; 485 | case STB_GLOBAL: bind = "STB_GLOBAL"; break; 486 | case STB_WEAK: bind = "STB_WEAK"; break; 487 | } 488 | const char* types = "*"; 489 | switch (ELF32_ST_TYPE(symbols[sym].st_info)) { 490 | case STT_NOTYPE: types = "STT_NOTYPE"; break; 491 | case STT_OBJECT: types = "STT_OBJECT"; break; 492 | case STT_FUNC: types = "STT_FUNC"; break; 493 | case STT_SECTION: types = "STT_SECTION"; break; 494 | case STT_FILE: types = "STT_FILE"; break; 495 | } 496 | if (verbose) 497 | printf(" %3d %4x[%4x] %d %3d %-20s %-10s %-10s %4x %4x %x %-s %x\n", 498 | j, (u32)tr[j].r_offset, (u32)(secoff + tr[j].r_offset), type, sym, &symbolNames[symbols[sym].st_name], 499 | bind, types, (u32)symbols[sym].st_value, (u32)symbols[sym].st_size, 500 | symbols[sym].st_other, symbols[sym].st_shndx < obj.SectionCount() ? obj.GetSection(symbols[sym].st_shndx)->Name().c_str() : "*", 501 | symbols[sym].st_shndx); 502 | u32 sec = st[sym].st_shndx; 503 | if (sec && sec < obj.SectionCount()) { 504 | b = base + sections[obj.GetSection(st[sym].st_shndx)->Name()] + symbols[sym].st_value; 505 | } else if (sec == SHN_COMMON) { 506 | b = base + commonbase + common[st[sym].st_name]; 507 | } else if (sec == 0) { 508 | u32 func = 0; 509 | for (const std::string& imp : imports) { 510 | if (imp == &symbolNames[symbols[sym].st_name]) break; 511 | ++func; 512 | } 513 | b = hashoff + 14 * func + base; 514 | } else { 515 | printf("Unknown section %x\n", sec); 516 | } 517 | if (type == R_X86_64_64) { 518 | *(u64*)off += b + 0x10000 + tr[j].r_addend; 519 | } else if (type == R_X86_64_32) { 520 | *off += b + 0x10000 + tr[j].r_addend; 521 | } else if (type == R_X86_64_PC32) { 522 | *off += b - tr[j].r_offset - secoff - base + tr[j].r_addend; 523 | } else { 524 | printf("Unknown type %d\n", type); 525 | } 526 | } 527 | } 528 | } 529 | 530 | FILE* tmpout = fopen("test/tmp", "wb"); 531 | fwrite(finalout, finalsize, 1, tmpout); 532 | fclose(tmpout); 533 | 534 | u8* bin = (u8*)malloc(65536); 535 | u8* data = (u8*)malloc(65536); 536 | int ds = 65536; 537 | Compressor* c = new Compressor(); 538 | CompressionParameters params; 539 | params.FromString(FlagWithDefault('c', "")); 540 | c->Compress(¶ms, finalout, finalsize, data + 8, &ds); 541 | Invert(data + 8, ds); 542 | memcpy(data, &Header()[sz - 8], 8); 543 | 544 | // Sanity check our compressed data by decompressing it again. 545 | memset(bin, 0, 65536); 546 | c->Decompress(¶ms, &data[8 + ds - 4], bin + 8, finalsize); 547 | if (memcmp(finalout, bin + 8, finalsize)) { 548 | printf("Decompression failed, first 10 different bytes\n"); 549 | int c = 0; 550 | for (int i = 0; i < finalsize; ++i) { 551 | if (finalout[i] != bin[i + 8]) { 552 | printf("%6x: %2.2x != %2.2x\n", i, finalout[i], bin[i + 8]); 553 | c++; 554 | if (c == 10) break; 555 | } 556 | } 557 | } 558 | memcpy(bin, Header(), sz); 559 | memcpy(&bin[sz], data + 8, ds); 560 | sz += ds; 561 | // Set pointer to last 4 bytes of compressed data in code. The address may 562 | // need adjusting if the header assembly changes. 563 | if (bits == 32) { 564 | *(u32*)&bin[0xd8] = 0x08000000 + sz - 4; 565 | } else { 566 | *(u32*)&bin[0x169] = 0x08000000 + sz - 4; 567 | } 568 | // Place size of decompressed data in bits at end of image. 569 | *(u32*)&bin[sz] = finalsize * 8; 570 | // Add compression parameters to end of image. 571 | memcpy(&bin[sz + 4], params.weights, params.contextCount); 572 | memcpy(&bin[sz + 4 + params.contextCount], params.contexts, params.contextCount); 573 | sz += 4 + 2 * params.contextCount; 574 | // Place file size in ELF header. 575 | if (bits == 32) { 576 | *(u32*)&bin[0x7c] = sz; 577 | } else { 578 | *(u64*)&bin[0xc8] = sz; 579 | } 580 | 581 | FILE* fptr = fopen(FlagWithDefault('o', "c.out"), "wb"); 582 | fwrite(bin, sz, 1, fptr); 583 | fclose(fptr); 584 | printf("Wrote %d bytes\n", sz); 585 | } 586 | private: 587 | inline const u8* Header(); 588 | inline u32 HeaderSize(); 589 | }; 590 | 591 | template<> const u8* Linker<32>::Header() { return header32; } 592 | template<> const u8* Linker<64>::Header() { return header64; } 593 | template<> u32 Linker<32>::HeaderSize() { return sizeof(header32); } 594 | template<> u32 Linker<64>::HeaderSize() { return sizeof(header64); } 595 | 596 | int main(int argc, char* argv[]) { 597 | for (int i = 1; i < argc; ++i) { 598 | if (argv[i][0] == '-') { 599 | if (argv[i][1]) { 600 | args[argv[i][1]].insert(std::string(&argv[i][2])); 601 | } 602 | } else { 603 | args['i'].insert(argv[i]); 604 | } 605 | } 606 | verbose = HasFlag("verbose"); 607 | 608 | if (args['i'].size() == 0) { printf("No obj specified\n"); return 1; } 609 | const char* fn = args['i'].begin()->c_str(); 610 | MemFile o; 611 | if (!o.Load(fn)) { 612 | return 0; 613 | } 614 | u16 arch = *(u16*)&o.Data()[18]; 615 | if (arch == 3) { 616 | printf("Arch: i386\n"); 617 | Linker<32> l; 618 | l.Link(&o); 619 | } else if (arch == 62) { 620 | printf("Arch: x86_64\n"); 621 | Linker<64> l; 622 | l.Link(&o); 623 | } else { 624 | printf("Cannot handle architecture in %s (arch = %2.2x)\n", fn, arch); 625 | return 1; 626 | } 627 | } 628 | -------------------------------------------------------------------------------- /flow2.c: -------------------------------------------------------------------------------- 1 | // Port of flow2 to be compiled and linked by dnload.py, platform-independent. 2 | // Both original comments and those from Amand Tihon copied verbatim. 3 | 4 | // This has been ported back to not requiring dnload.py, so that it can be linked 5 | // by elfling. 6 | 7 | // Linux x86_64 port of flow2, to be linked with the bold linker. 8 | // Ported by Amand Tihon (alrj). 9 | // Original comments in flow2 source code copied verbatim 10 | 11 | // Chris Thornborrow (auld/sek/taj/copabars) 12 | // If you use this code please credit...blahblah 13 | // Example OGL + shaders in 1k 14 | // Requires crinkler - magnificent tool 15 | // VS2005 modifications by benny!weltenkonstrukteur.de from dbf 16 | // Greets! 17 | // NOTE: DX will beat this no problem at all due to OpenGL forced 18 | // to import shader calls as variables..nontheless we dont need 19 | // d3dxblahblah to be loaded on users machine. 20 | 21 | #include 22 | #include 23 | 24 | // NOTE: in glsl it is legal to have a fragment shader without a vertex shader 25 | // Infact ATi/AMD drivers allow this but unwisely forget to set up variables for 26 | // the fragment shader - thus all GLSL programs must have a vertex shader :-( 27 | // Thanks ATI/AMD 28 | 29 | // This is pretty dirty...note we do not transform the rectangle but we do use 30 | // glRotatef to pass in a value we can use to animate...avoids one more getProcAddress later 31 | const GLchar *vsh="\ 32 | varying vec4 p;\ 33 | void main(){\ 34 | p=sin(gl_ModelViewMatrix[1]*9.0);\ 35 | gl_Position=gl_Vertex;\ 36 | }"; 37 | 38 | // an iterative function for colour 39 | const GLchar *fsh="\ 40 | varying vec4 p;\ 41 | void main(){\ 42 | float r,t,j;\ 43 | vec4 v=gl_FragCoord/400.0-1.0;\ 44 | r=v.x*p.r;\ 45 | for(int j=0;j<7;j++){\ 46 | t=v.x+p.r*p.g;\ 47 | v.x=t*t-v.y*v.y+r;\ 48 | v.y=p.g*3.0*t*v.y+v.y;\ 49 | }\ 50 | gl_FragColor=vec4(mix(p,vec4(t),max(t,v.x)));\ 51 | }"; 52 | //p.g*3.0*t*v.y+i;\ 53 | 54 | static void setShaders() { 55 | 56 | GLuint v = glCreateShader(GL_VERTEX_SHADER); 57 | GLuint f = glCreateShader(GL_FRAGMENT_SHADER); 58 | GLuint p = glCreateProgram(); 59 | 60 | glShaderSource(v, 1, &vsh, NULL); 61 | glCompileShader(v); 62 | glAttachShader(p, v); 63 | glShaderSource(f, 1, &fsh, NULL); 64 | glCompileShader(f); 65 | glAttachShader(p, f); 66 | glLinkProgram(p); 67 | glUseProgram(p); 68 | } 69 | 70 | void _start() 71 | { 72 | static SDL_Event e; 73 | SDL_Init(SDL_INIT_VIDEO); 74 | SDL_SetVideoMode(1024, 768, 0, SDL_OPENGL); 75 | 76 | SDL_ShowCursor(SDL_DISABLE); 77 | setShaders(); 78 | //********************** 79 | // NOW THE MAIN LOOP... 80 | //********************** 81 | // there is no depth test or clear screen...as we draw in order and cover 82 | // the whole area of the screen. 83 | do 84 | { 85 | glRotatef(0.3f, 1, 1, 1); 86 | glRecti(-1, -1, 1, 1); 87 | SDL_GL_SwapBuffers(); 88 | 89 | SDL_PollEvent(&e); 90 | 91 | if (e.type == SDL_KEYDOWN) 92 | break; 93 | } while (e.type != SDL_QUIT); 94 | 95 | __asm ("mov $1, %eax\n" 96 | "xor %ebx, %ebx\n" 97 | "int $0x80"); 98 | } 99 | -------------------------------------------------------------------------------- /header.asm: -------------------------------------------------------------------------------- 1 | ; Copyright 2014 Google Inc. All Rights Reserved. 2 | ; 3 | ; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ; you may not use this file except in compliance with the License. 5 | ; You may obtain a copy of the License at 6 | ; 7 | ; http://www.apache.org/licenses/LICENSE-2.0 8 | ; 9 | ; Unless required by applicable law or agreed to in writing, software 10 | ; distributed under the License is distributed on an "AS IS" BASIS, 11 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ; See the License for the specific language governing permissions and 13 | ; limitations under the License. 14 | ; 15 | ; elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | bits 32 18 | base equ 0x08000000 19 | ccount equ 8 ; Number of contexts. 20 | 21 | ; Elf32_Ehdr 22 | db 0x7f, 'ELF' ; e_ident (the part that is validated) 23 | ; db 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; e_ident (the part no one cares about) 24 | strtab: 25 | db 0 ; e_ident (the part no one cares about), initial zero of strtab 26 | libgl: 27 | db 'libGL.so.1', 0 ; Ideally I'd like to find a lib that includes both this and SDL, but there is none :-( 28 | dw 2 ; e_type ET_EXEC 29 | dw 3 ; e_machine EM_386 30 | dd 1 ; e_version EV_CURRENT 31 | dd base + entry ; e_entry 32 | dd phoff ; e_phoff 33 | dd 0 ; e_shoff (ignored) 34 | dd 0 ; e_flags 35 | dw 0x34 ; e_ehsize 36 | dw 0x20 ; e_phentsize 37 | ; The following 4 fields can overlap with the first phdr, since they are not validated, and 38 | ; e_phnum happens to have the same value as PT_INTERP.. 39 | ;dw 3 ; e_phnum 40 | ;dw 0 ; e_shentsize 41 | ;dw 0 ; e_shnum 42 | ;dw 0 ; e_shstrndx 43 | 44 | ; Elf32_Phdr, 3 times. 45 | ; This is the biggest space-waster here, but we need one for the interpreter, one for the dynamic 46 | ; table, and one for the actual loaded data (which can group everything else, and be writable). 47 | phoff: 48 | dd 3 ; p_type PT_INTERP 49 | dd interp ; p_offset 50 | dd base + interp ; p_vaddr 51 | dd 0 ; p_paddr (ignored) 52 | dd 19 ; p_filesz 53 | dd 19 ; p_memsz 54 | dd 4 ; p_flags PF_R 55 | dd 1 ; p_align 56 | 57 | dd 2 ; p_type PT_DYNAMIC 58 | dd dynamic ; p_offset 59 | dd base + dynamic ; p_vaddr 60 | dd 0 ; p_paddr (ignored) 61 | dd 6 * 8 ; p_filesz 62 | dd 6 * 8 ; p_memsz 63 | dd 4 ; p_flags PF_R 64 | dd 1 ; p_align 65 | 66 | dd 1 ; p_type PT_LOAD 67 | dd 0 ; p_offset 68 | dd base ; p_vaddr 69 | dd 0 ; p_paddr (ignored) 70 | dd 0xffffffff ; p_filesz, replaced by elfling 71 | dd 161 * 1024 * 1024 ; p_memsz 72 | dd 7 ; p_flags PF_R | PF_W | PF_X 73 | ; dd 1 ; p_align 74 | 75 | dynamic: ; Overlap align of last ph with DT_NEEDED, which has the same value 76 | dd 1 ; DT_NEEDED 77 | dd libgl - strtab 78 | dd 1 ; DT_NEEDED 79 | dd libsdl - strtab 80 | dd 0x15 ; DT_DEBUG 81 | debug: 82 | dd 0 83 | dd 5 ; DT_STRTAB 84 | dd strtab + base 85 | dd 6 ; DT_SYMTAB 86 | dd strtab + base 87 | dd 0 ; DT_NULL 88 | ;dd 0 ; This can be a random value. 89 | 90 | interp: 91 | db '/lib/ld-linux.so.2', 0 92 | libsdl: 93 | db 'libSDL-1.2.so.0', 0 ; Gets us libc, but no OpenGL. 94 | 95 | v_dataend equ 0 ; Last dword of compressed data 96 | v_osize equ 4 ; This is written in by elfling 97 | v_weights equ 8 ; This is written in by elfling 98 | v_contexts equ v_weights + ccount ; This is written in by elfling 99 | v_archive equ v_contexts + ccount ; This is the start of our runtime variables 100 | v_x2 equ v_archive + 4 101 | v_x1 equ v_x2 + 4 102 | v_cp equ v_x1 + 4 103 | v_counters equ v_cp + 4 * ccount 104 | 105 | entry: 106 | ; The destination is placed at 64k, so the compressed data cannot be larger than that. We also need 107 | ; some space for the variables. 108 | mov ebp, 0xffffffff ; Keep variables just after compressed data, replaced by elfling 109 | mov edi, base + 0x10000 ; Dest [keep in edi] 110 | push edi ; Push dest address for jumping to when we have finished decompression. 111 | inc byte [edi] ; Set first output byte to 1. 112 | mov dword [ebp + v_archive], ebp ; Current input pointer. 113 | 114 | xor ecx, ecx 115 | mov cl, ccount 116 | mov dl, 9 117 | .nextCounter: 118 | mov byte [ebp + v_counters + ecx * 4 - 4 + 3], dl ; Address is 0x09000000 (and then 0x0a, 0x0b, 0x0c, ...) 119 | mov byte [ebp + v_cp + ecx * 4 - 4 + 3], dl 120 | inc dl 121 | loop .nextCounter 122 | 123 | mov [ebp + v_x1], ecx ; x1 = 0 124 | dec ecx 125 | mov [ebp + v_x2], ecx ; x2 = 0xffffffff 126 | inc ecx 127 | 128 | .iterate: 129 | xor eax, eax 130 | xor edx, edx 131 | inc edx ; n0 = 1 [edx] 132 | lea ebx, [2 * edx] ; n0 + n1 = 2 [ebx] 133 | mov cl, ccount 134 | .nextweight: 135 | mov esi, [ebp + v_cp + ecx * 4 - 4] 136 | lodsb 137 | mul byte [ebp + v_weights + ecx - 1] 138 | add edx, eax ; n0 139 | add ebx, eax ; n0 + n1 140 | lodsb 141 | mul byte [ebp + v_weights + ecx - 1] 142 | add ebx, eax ; n0 + n1 143 | loop .nextweight 144 | 145 | ; u32 xmid = x1 + n0 * (u64)(x2 - x1) / (n0 + n1); 146 | mov eax, edx ; n0 [eax] 147 | mov edx, [ebp + v_x2] 148 | sub edx, [ebp + v_x1] ; (x2 - x1) [edx] 149 | mul edx 150 | div ebx 151 | add eax, [ebp + v_x1] ; xmid [eax] 152 | 153 | xor edx, edx 154 | mov esi, [ebp + v_archive] ; archive 155 | cmp eax, [esi] ; Compare *(u32*)archive with xmid 156 | jb .isone ; The comparison sets the carry flag the way we want to, set if our bit is a one, clear otherwise. jb jumps on carry as desired (JB = JC). 157 | mov [ebp + v_x2], eax 158 | jmp .iszero 159 | .isone: 160 | inc eax 161 | mov [ebp + v_x1], eax 162 | inc edx 163 | .iszero: 164 | 165 | rcl byte[edi], 1 ; Shift top bit of edi into carry, shift in carry (which contains the bit we want to add). 166 | jnc .notyet ; If we shifted out a one, the byte is complete, move on to next byte. 167 | inc edi 168 | inc byte [edi] 169 | .notyet: 170 | 171 | mov cl, ccount 172 | .nextmodel: 173 | mov esi, [ebp + v_cp + ecx * 4 - 4] 174 | add esi, edx ; Select counter matching our bit 175 | add byte[esi], 1 ; Increment counter by one 176 | sbb byte[esi], 0 ; If we overflow, return it to 255 177 | xor esi, 1 ; Select the other counter. 178 | cmp byte [esi], 2 179 | jb .noadjust 180 | shr byte [esi], 1 181 | inc byte [esi] 182 | .noadjust: 183 | xor eax, eax 184 | mov bl, 1 ; Mask bit 185 | mov bh, [ebp + v_contexts + ecx - 1] 186 | .nextcontextbyte: 187 | test bh, bl 188 | jz .notused 189 | shl eax, 8 190 | mov al, byte [edi] 191 | .notused: 192 | dec edi 193 | shl bl, 1 194 | jnz .nextcontextbyte 195 | add edi, 8 196 | mov esi, [ebp + v_counters + ecx * 4 - 4] 197 | .nextval: 198 | cmp dword [esi], eax 199 | je .foundentry 200 | cmp dword [esi], 0 201 | je .foundentry 202 | add esi, 6 203 | jmp .nextval 204 | .foundentry: 205 | mov dword [esi], eax 206 | add esi, 4 207 | mov [ebp + v_cp + ecx * 4 - 4], esi 208 | loop .nextmodel 209 | 210 | .killbits: 211 | mov edx, [ebp + v_x1] 212 | xor edx, [ebp + v_x2] 213 | shr edx, 24 214 | jnz .donekilling 215 | shl dword [ebp + v_x1], 8 216 | shl dword [ebp + v_x2], 8 217 | dec byte [ebp + v_x2] 218 | dec dword [ebp + v_archive] 219 | jmp .killbits 220 | .donekilling: 221 | dec dword [ebp + v_osize] ; Size 222 | jnz .iterate 223 | ret 224 | 225 | db'XXXX-Compressed code here-XXXX' 226 | 227 | ; The code that comes after here is actually compressed. It contains the dynamic linker. 228 | 229 | compentry: 230 | mov ebp, base + 0x10000 + .hashes - compentry + 1 231 | .nexthash: 232 | mov ebx, base + debug ; DT_DEBUG value offset 233 | mov ebx, [ebx] ; Load debug table offset 234 | mov ebx, [ebx + 4] ; Load pointer to first library (r_map), ebx points to library structure. 235 | xor eax, eax ; al is used for loading chars in function name, we need upper bits to be zero for hashing. 236 | .nextlib: 237 | mov esi, [ebx + 4] ; Point esi to library name 238 | or byte [esi], al ; If library name is empty, we skip it. Weird things live there. 239 | jz .nameless 240 | 241 | mov ecx, [ebx + 8] ; l_ld, use ecx for walking through dynamic table 242 | .nt: 243 | add ecx, 8 ; Assume that the dynamic table never starts off with DT_STRTAB. This is true for all libraries I looked at. 244 | cmp byte [ecx], 5 ; DT_STRTAB 245 | jne .nt 246 | 247 | .found: 248 | mov edx, [ecx + 4] ; String base [edx] 249 | mov ecx, [ecx + 12] ; Symbols [ecx]. Assume that this immediately follows DT_STRTAB 250 | .nsym: 251 | mov esi, [ecx] ; Read symbol name offset (st_name) 252 | add esi, edx ; Add string table offset. 253 | xor edi, edi ; Hash = 0 254 | .nchar: 255 | lodsb ; Read char from symbol name. 256 | xor edi, eax 257 | rol edi, 5 258 | test al, al ; Test if null terminator 259 | jnz .nchar 260 | cmp edi, dword [ebp] ; Hash of import. 261 | je .hashfound 262 | 263 | .nf: 264 | add ecx, 16 265 | cmp ecx, edx 266 | jb .nsym 267 | 268 | .nameless: 269 | mov ebx, [ebx + 12] ; l_next 270 | jmp .nextlib ; We don't know how to handle symbols that can't be found. Just continuing will cause us to crash. 271 | 272 | .hashfound: 273 | mov edi, [ecx + 4] ; st_value 274 | test edi, edi ; Test if zero 275 | jz .nf ; And reject any symbols with zero value. 276 | add edi, [ebx] ; l_addr 277 | sub edi, ebp 278 | sub edi, 4 279 | mov [ebp], edi 280 | add ebp, 5 281 | cmp dword [ebp], 0 282 | jnz .nexthash 283 | jmp 0x12345678 ; Jump to real entry point. 284 | 285 | .hashes: 286 | ; The hash table is placed here. 287 | 288 | -------------------------------------------------------------------------------- /header64.asm: -------------------------------------------------------------------------------- 1 | ; Copyright 2014 Google Inc. All Rights Reserved. 2 | ; 3 | ; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ; you may not use this file except in compliance with the License. 5 | ; You may obtain a copy of the License at 6 | ; 7 | ; http://www.apache.org/licenses/LICENSE-2.0 8 | ; 9 | ; Unless required by applicable law or agreed to in writing, software 10 | ; distributed under the License is distributed on an "AS IS" BASIS, 11 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ; See the License for the specific language governing permissions and 13 | ; limitations under the License. 14 | ; 15 | ; elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | bits 64 18 | base equ 0x08000000 19 | ccount equ 8 ; Number of contexts. 20 | 21 | ; Elf32_Ehdr 22 | db 0x7f, 'ELF' ; e_ident (the part that is validated) 23 | db '123456789012' 24 | ; db 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; e_ident (the part no one cares about) 25 | dw 2 ; e_type ET_EXEC 26 | dw 62 ; e_machine EM_X86_64 27 | dd 1 ; e_version EV_CURRENT 28 | dq base + entry ; e_entry 29 | dq phoff ; e_phoff 30 | dq 0 ; e_shoff (ignored) 31 | dd 0 ; e_flags 32 | dw 0x40 ; e_ehsize 33 | dw 0x38 ; e_phentsize 34 | ; The following 4 fields can overlap with the first phdr, since they are not validated, and 35 | ; e_phnum happens to have the same value as PT_INTERP.. 36 | ;dw 3 ; e_phnum 37 | ;dw 0 ; e_shentsize 38 | ;dw 0 ; e_shnum 39 | ;dw 0 ; e_shstrndx 40 | 41 | ; Elf32_Phdr, 3 times. 42 | ; This is the biggest space-waster here, but we need one for the interpreter, one for the dynamic 43 | ; table, and one for the actual loaded data (which can group everything else, and be writable). 44 | phoff: 45 | dd 3 ; p_type PT_INTERP 46 | dd 4 ; p_flags PF_R 47 | dq interp ; p_offset 48 | dq base + interp ; p_vaddr 49 | dq 0 ; p_paddr (ignored) 50 | dq libsdl - interp ; p_filesz 51 | dq libsdl - interp ; p_memsz 52 | dq 1 ; p_align 53 | 54 | dd 2 ; p_type PT_DYNAMIC 55 | dd 4 ; p_flags PF_R 56 | dq dynamic ; p_offset 57 | dq base + dynamic ; p_vaddr 58 | dq 0 ; p_paddr (ignored) 59 | dummy: 60 | dq 6 * 8 ; p_filesz 61 | dq 6 * 8 ; p_memsz 62 | dq 1 ; p_align 63 | 64 | dd 1 ; p_type PT_LOAD 65 | dd 7 ; p_flags PF_R | PF_W | PF_X 66 | dq 0 ; p_offset 67 | dq base ; p_vaddr 68 | dq 0 ; p_paddr (ignored) 69 | dq 0xffffffffffffffff ; p_filesz, replaced by elfling 70 | dq 161 * 1024 * 1024 ; p_memsz 71 | ; dq 1 ; p_align 72 | 73 | dynamic: ; Overlap align of last ph with DT_NEEDED, which has the same value 74 | dq 1 ; DT_NEEDED 75 | dq libgl - strtab 76 | dq 1 ; DT_NEEDED 77 | dq libsdl - strtab 78 | dq 0x15 ; DT_DEBUG 79 | debug: 80 | dq 0 81 | dq 5 ; DT_STRTAB 82 | dq strtab + base 83 | dq 6 ; DT_SYMTAB 84 | dq strtab + base 85 | dq 0 ; DT_NULL 86 | ;dd 0 ; This can be a random value. 87 | 88 | interp: 89 | db '/lib64/ld-linux-x86-64.so.2', 0 90 | strtab: 91 | db 0 ; e_ident (the part no one cares about), initial zero of strtab 92 | libgl: 93 | db 'libGL.so.1', 0 ; Ideally I'd like to find a lib that includes both this and SDL, but there is none :-( 94 | libsdl: 95 | db 'libSDL-1.2.so.0', 0 ; Gets us libc, but no OpenGL. 96 | 97 | v_dataend equ 0 ; Last dword of compressed data 98 | v_osize equ 4 ; This is written in by elfling 99 | v_weights equ 8 ; This is written in by elfling 100 | v_contexts equ v_weights + ccount ; This is written in by elfling 101 | v_archive equ v_contexts + ccount ; This is the start of our runtime variables 102 | v_x2 equ v_archive + 4 103 | v_x1 equ v_x2 + 4 104 | v_cp equ v_x1 + 4 105 | v_counters equ v_cp + 4 * ccount 106 | 107 | entry: 108 | ; The destination is placed at 64k, so the compressed data cannot be larger than that. We also need 109 | ; some space for the variables. 110 | mov ebp, 0xffffffff ; Keep variables just after compressed data, replaced by elfling 111 | mov edi, base + 0x10000 ; Dest [keep in edi] 112 | push rdi ; Push dest address for jumping to when we have finished decompression. 113 | inc byte [rdi] ; Set first output byte to 1. 114 | mov dword [rbp + v_archive], ebp ; Current input pointer. 115 | 116 | xor ecx, ecx 117 | mov cl, ccount 118 | mov dl, 9 119 | .nextCounter: 120 | mov byte [rbp + v_counters + rcx * 4 - 4 + 3], dl ; Address is 0x09000000 (and then 0x0a, 0x0b, 0x0c, ...) 121 | mov byte [rbp + v_cp + rcx * 4 - 4 + 3], dl 122 | inc dl 123 | loop .nextCounter 124 | 125 | mov [rbp + v_x1], ecx ; x1 = 0 126 | dec ecx 127 | mov [rbp + v_x2], ecx ; x2 = 0xffffffff 128 | inc ecx 129 | 130 | .iterate: 131 | xor eax, eax 132 | xor edx, edx 133 | inc edx ; n0 = 1 [edx] 134 | lea ebx, [2 * edx] ; n0 + n1 = 2 [ebx] 135 | mov cl, ccount 136 | .nextweight: 137 | mov esi, [rbp + v_cp + rcx * 4 - 4] 138 | lodsb 139 | mul byte [rbp + v_weights + rcx - 1] 140 | add edx, eax ; n0 141 | add ebx, eax ; n0 + n1 142 | lodsb 143 | mul byte [rbp + v_weights + rcx - 1] 144 | add ebx, eax ; n0 + n1 145 | loop .nextweight 146 | 147 | ; u32 xmid = x1 + n0 * (u64)(x2 - x1) / (n0 + n1); 148 | mov eax, edx ; n0 [eax] 149 | mov edx, [rbp + v_x2] 150 | sub edx, [rbp + v_x1] ; (x2 - x1) [edx] 151 | mul edx 152 | div ebx 153 | add eax, [rbp + v_x1] ; xmid [eax] 154 | 155 | xor edx, edx 156 | mov esi, [rbp + v_archive] ; archive 157 | cmp eax, [rsi] ; Compare *(u32*)archive with xmid 158 | jb .isone ; The comparison sets the carry flag the way we want to, set if our bit is a one, clear otherwise. jb jumps on carry as desired (JB = JC). 159 | mov [rbp + v_x2], eax 160 | jmp .iszero 161 | .isone: 162 | inc eax 163 | mov [rbp + v_x1], eax 164 | inc edx 165 | .iszero: 166 | 167 | rcl byte[edi], 1 ; Shift top bit of edi into carry, shift in carry (which contains the bit we want to add). 168 | jnc .notyet ; If we shifted out a one, the byte is complete, move on to next byte. 169 | inc edi 170 | inc byte [edi] 171 | .notyet: 172 | 173 | mov cl, ccount 174 | .nextmodel: 175 | mov esi, [rbp + v_cp + rcx * 4 - 4] 176 | add esi, edx ; Select counter matching our bit 177 | add byte[rsi], 1 ; Increment counter by one 178 | sbb byte[rsi], 0 ; If we overflow, return it to 255 179 | xor esi, 1 ; Select the other counter. 180 | cmp byte [rsi], 2 181 | jb .noadjust 182 | shr byte [rsi], 1 183 | inc byte [rsi] 184 | .noadjust: 185 | xor eax, eax 186 | mov bl, 1 ; Mask bit 187 | mov bh, [rbp + v_contexts + rcx - 1] 188 | .nextcontextbyte: 189 | test bh, bl 190 | jz .notused 191 | shl eax, 8 192 | mov al, byte [rdi] 193 | .notused: 194 | dec edi 195 | shl bl, 1 196 | jnz .nextcontextbyte 197 | add edi, 8 198 | mov esi, [rbp + v_counters + rcx * 4 - 4] 199 | .nextval: 200 | cmp dword [rsi], eax 201 | je .foundentry 202 | cmp dword [rsi], 0 203 | je .foundentry 204 | add esi, 6 205 | jmp .nextval 206 | .foundentry: 207 | mov dword [rsi], eax 208 | add esi, 4 209 | mov [rbp + v_cp + rcx * 4 - 4], esi 210 | loop .nextmodel 211 | 212 | .killbits: 213 | mov edx, [rbp + v_x1] 214 | xor edx, [rbp + v_x2] 215 | shr edx, 24 216 | jnz .donekilling 217 | shl dword [rbp + v_x1], 8 218 | shl dword [rbp + v_x2], 8 219 | dec byte [rbp + v_x2] 220 | dec dword [rbp + v_archive] 221 | jmp .killbits 222 | .donekilling: 223 | dec dword [rbp + v_osize] ; Size 224 | jnz .iterate 225 | ret 226 | 227 | db'XXXX-Compressed code here-XXXX' 228 | 229 | ; The code that comes after here is actually compressed. It contains the dynamic linker. 230 | 231 | compentry: 232 | mov ebp, base + 0x10000 + .hashes - compentry + 6 233 | .nexthash: 234 | mov ebx, base + debug ; DT_DEBUG value offset 235 | mov rbx, [rbx] ; Load debug table offset 236 | mov rbx, [rbx + 8] ; Load pointer to first library (r_map), ebx points to library structure. 237 | xor eax, eax ; al is used for loading chars in function name, we need upper bits to be zero for hashing. 238 | .nextlib: 239 | mov rsi, [rbx + 8] ; Point esi to library name 240 | or byte [rsi], al ; If library name is empty, we skip it. Weird things live there. 241 | jz .nameless 242 | 243 | mov rcx, [rbx + 16] ; l_ld, use ecx for walking through dynamic table 244 | .nt: 245 | add rcx, 16 ; Assume that the dynamic table never starts off with DT_STRTAB. This is true for all libraries I looked at. 246 | cmp byte [rcx], 5 ; DT_STRTAB 247 | jne .nt 248 | 249 | .found: 250 | mov rdx, [rcx + 8] ; String base [edx] 251 | mov rcx, [rcx + 24] ; Symbols [ecx]. Assume that this immediately follows DT_STRTAB 252 | .nsym: 253 | mov esi, dword [rcx] ; Read symbol name offset (st_name) 254 | add rsi, rdx ; Add string table offset. 255 | xor edi, edi ; Hash = 0 256 | .nchar: 257 | lodsb ; Read char from symbol name. 258 | xor edi, eax 259 | rol edi, 5 260 | test al, al ; Test if null terminator 261 | jnz .nchar 262 | cmp edi, dword [rbp] ; Hash of import. 263 | je .hashfound 264 | 265 | .nf: 266 | add rcx, 24 ; Move to next symbol (sizeof(Elf64_Sym) = 24) 267 | cmp rcx, rdx 268 | jb .nsym 269 | 270 | .nameless: 271 | mov rbx, [rbx + 24] ; l_next 272 | jmp .nextlib ; We don't know how to handle symbols that can't be found. Just continuing will cause us to crash. 273 | 274 | .hashfound: 275 | mov rdi, [rcx + 8] ; st_value 276 | test rdi, rdi ; Test if zero 277 | jz .nf ; And reject any symbols with zero value. 278 | add rdi, [rbx] ; l_addr 279 | mov [rbp], rdi 280 | add rbp, 14 281 | cmp dword [rbp], 0 282 | jnz .nexthash 283 | jmp 0xffffffff ; Jump to real entry point. 284 | 285 | 286 | .hashes: 287 | ; The hash table is placed here. 288 | 289 | 290 | fileend: 291 | -------------------------------------------------------------------------------- /pack.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | #include "pack.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | int cmax = 0; 25 | 26 | #define CONTEXT_COUNT 8 27 | 28 | #define GENOME_SIZE 48 29 | #define GENOME_ITERATIONS 100 30 | 31 | #define MAX_WEIGHT 60 32 | 33 | int FromHexDigit(char d) { 34 | if (d >= '0' && d <= '9') return d - '0'; 35 | if (d >= 'A' && d <= 'F') return d - 'A' + 10; 36 | if (d >= 'a' && d <= 'f') return d - 'a' + 10; 37 | return -1; 38 | } 39 | 40 | int FromHex2(const char* str) { 41 | int d0 = FromHexDigit(str[0]); 42 | int d1 = FromHexDigit(str[1]); 43 | if (d0 < 0 || d1 < 0) return -1; 44 | return d0 * 16 + d1; 45 | } 46 | 47 | void ToHex2(int v, char* dst) { 48 | const char* hd = "0123456789abcdef"; 49 | dst[0] = hd[(v >> 4) & 0x0f]; 50 | dst[1] = hd[v & 0x0f]; 51 | } 52 | 53 | bool CompressionParameters::FromString(const char* str) { 54 | int l = strlen(str); 55 | if (l < 10) return false; // Expect at least two contexts. 56 | contextCount = FromHex2(str); 57 | if (contextCount < 2 || contextCount > MAX_CONTEXT_COUNT) return false; 58 | if (l != 2 + 4 * contextCount) return false; 59 | for (int i = 0; i < contextCount; ++i) { 60 | weights[i] = FromHex2(str + 2 + 4 * i); 61 | contexts[i] = FromHex2(str + 4 + 4 * i); 62 | } 63 | return true; 64 | } 65 | 66 | void CompressionParameters::ToString(char* str) { 67 | ToHex2(contextCount, str); 68 | for (int i = 0; i < contextCount; ++i) { 69 | ToHex2(weights[i], str + 2 + 4 * i); 70 | ToHex2(contexts[i], str + 4 + 4 * i); 71 | } 72 | str[2 + 4 * contextCount] = 0; 73 | } 74 | 75 | struct Context { 76 | u8 ctx; 77 | int bs; 78 | int bw; 79 | }; 80 | 81 | static int CompareContext(const Context* a, const Context* b) { 82 | return a->bs - b->bs; 83 | } 84 | 85 | struct Genome { 86 | CompressionParameters params; 87 | int fitness; 88 | }; 89 | 90 | static int CompareGenome(const Genome* a, const Genome* b) { 91 | if (a->fitness != b->fitness) { 92 | return a->fitness - b->fitness; 93 | } 94 | for (int i = 0; i < CONTEXT_COUNT; ++i) { 95 | if (a->params.weights[i] != b->params.weights[i]) 96 | return a->params.weights[i] - b->params.weights[i]; 97 | if (a->params.contexts[i] != b->params.contexts[i]) 98 | return a->params.contexts[i] - b->params.contexts[i]; 99 | } 100 | return 0; 101 | } 102 | 103 | bool Compressor::Compress(CompressionParameters* params, void* in, int inLen, void* out, int* outLen) { 104 | // Test all context patterns individually to figure out which ones are most 105 | // likely to produce good results for seeding our initial set. 106 | Context pats[128]; 107 | u32 pc = 0; 108 | int orgOutLen = *outLen; 109 | for (u32 i = 3; i < 256; i += 2) { 110 | u32 bc = 0; 111 | for (u8 b = 0; b < 8; ++b) { 112 | if (i & (1 << b)) ++bc; 113 | } 114 | if (bc > 4) continue; // Only keep patterns with 4 bytes at most. 115 | pats[pc].ctx = i; 116 | pats[pc].bs = *outLen; 117 | pats[pc].bw = 0; 118 | CompressionParameters c; 119 | c.contextCount = 2; 120 | c.weights[0] = 8; 121 | c.weights[1] = 1; 122 | c.contexts[0] = pats[pc].ctx; 123 | c.contexts[1] = 1; 124 | CompressSingle(&c, in, inLen, out, &pats[pc].bs); 125 | ++pc; 126 | } 127 | qsort(pats, pc, sizeof(Context), (__compar_fn_t)CompareContext); 128 | if (verbose_) { 129 | for (int i = 0; i < pc; ++i) { 130 | printf("Pattern %2d [%2.2x] = %d bytes @ %d\n", i, pats[i].ctx, pats[i].bs, pats[i].bw); 131 | } 132 | } 133 | 134 | Genome* g = new Genome[GENOME_SIZE]; 135 | for (int i = 0; i < GENOME_SIZE; ++i) { 136 | g[i].params.contextCount = CONTEXT_COUNT; 137 | g[i].params.contexts[0] = 1; 138 | g[i].params.weights[0] = 1; 139 | for (int j = 1; j < CONTEXT_COUNT; ++j) { 140 | if (i == 0) { 141 | g[i].params.contexts[j] = pats[j - 1].ctx; 142 | g[i].params.weights[j] = 20; 143 | } else { 144 | g[i].params.contexts[j] = pats[rand() % (pc / 4)].ctx; 145 | g[i].params.weights[j] = rand() % MAX_WEIGHT + 1; 146 | } 147 | } 148 | } 149 | if (params->contextCount) { 150 | g[1].params = *params; 151 | } 152 | for (int i = 0; i < GENOME_ITERATIONS; ++i) { 153 | for (int j = 0; j < GENOME_SIZE; ++j) { 154 | g[j].fitness = *outLen; 155 | CompressSingle(&g[j].params, in, inLen, out, &g[j].fitness); 156 | } 157 | qsort(g, GENOME_SIZE, sizeof(Genome), (__compar_fn_t)CompareGenome); 158 | for (int j = 0; j < GENOME_SIZE; ++j) { 159 | if (j >= 3) break; 160 | printf("I[%3d,%d]: %d", i, j, g[j].fitness); 161 | for (int i = 0; i < g[j].params.contextCount; ++i) { 162 | printf(" %2d*%2.2x", g[j].params.weights[i], g[j].params.contexts[i]); 163 | } 164 | printf("\n"); 165 | } 166 | *params = g[0].params; 167 | srand(time(nullptr)); 168 | int keep = GENOME_SIZE / 4; 169 | for (int j = 0; j < GENOME_SIZE; ++j) { 170 | g[j].fitness = 0; 171 | } 172 | for (int j = keep; j < GENOME_SIZE / 2; j += 2) { 173 | int m1 = rand() % keep; 174 | int m2 = rand() % keep; 175 | while (m2 == m1) { m2 = rand() % keep; } 176 | int cb = rand() % (CONTEXT_COUNT * 2); 177 | bool equals = true; 178 | for (int k = 0; k < 2 * CONTEXT_COUNT; ++k) { 179 | u8* trg1 = (k & 1) ? g[j].params.contexts : g[j].params.weights; 180 | u8* trg2 = (k & 1) ? g[j + 1].params.contexts : g[j + 1].params.weights; 181 | u8* src1 = (k & 1) ? g[m1].params.contexts : g[m1].params.weights; 182 | u8* src2 = (k & 1) ? g[m2].params.contexts : g[m2].params.weights; 183 | if (k >= cb) { 184 | u8* tmp = src1; 185 | src1 = src2; 186 | src2 = tmp; 187 | } 188 | trg1[k >> 1] = src1[k >> 1]; 189 | trg2[k >> 1] = src2[k >> 1]; 190 | } 191 | } 192 | qsort(g, GENOME_SIZE / 2, sizeof(Genome), (__compar_fn_t)CompareGenome); 193 | for (int j = 1; j < GENOME_SIZE / 2; ++j) { 194 | if (!memcmp(g[j].params.weights, g[j - 1].params.weights, CONTEXT_COUNT) && !memcmp(g[j].params.contexts, g[j - 1].params.contexts, CONTEXT_COUNT)) { 195 | int byte = rand() % (2 * CONTEXT_COUNT); 196 | if (byte < CONTEXT_COUNT) { 197 | g[j - 1].params.contexts[byte] = pats[rand() % pc].ctx; 198 | } else { 199 | g[j - 1].params.weights[byte - CONTEXT_COUNT] = rand() % MAX_WEIGHT + 1; 200 | } 201 | } 202 | } 203 | for (int j = GENOME_SIZE / 2; j < GENOME_SIZE; ++j) { 204 | memcpy(&g[j], &g[j % keep], sizeof(Genome)); 205 | int limit = 1; 206 | if (j > 3 * GENOME_SIZE / 4) 207 | limit = 3; 208 | for (int k = 0; k < 3; ++k) { 209 | // Mutation. 210 | int byte = rand() % (2 * CONTEXT_COUNT); 211 | if (byte < CONTEXT_COUNT) { 212 | g[j].params.contexts[byte] = pats[rand() % pc].ctx; 213 | } else { 214 | g[j].params.weights[byte - CONTEXT_COUNT] = rand() % MAX_WEIGHT + 1; 215 | } 216 | } 217 | } 218 | } 219 | 220 | delete[] g; 221 | 222 | if (CompressSingle(params, in, inLen, out, outLen)) { 223 | printf("Final: %d", *outLen); 224 | for (int i = 0; i < params->contextCount; ++i) { 225 | printf(" %2d*%2.2x", params->weights[i], params->contexts[i]); 226 | } 227 | printf("\n"); 228 | printf("cmax: %d\n", cmax); 229 | char buf[128]; 230 | params->ToString(buf); 231 | printf("Params: %s\n", buf); 232 | return true; 233 | } 234 | printf("Failed, for some reason could not recompress with optimal settings\n"); 235 | return false; 236 | } 237 | 238 | bool Compressor::CompressSingle(CompressionParameters* comp, void* in, int inLen, void* out, int* outLen) { 239 | u8* archive = (u8*)in; 240 | u8* output; 241 | u8* counters[MAX_CONTEXT_COUNT]; // Counter base offsets 242 | u8* cp[MAX_CONTEXT_COUNT]; // Current counters 243 | u8 tbuf[8] = {1, 0, 0, 0, 0, 0, 0, 0}; 244 | 245 | memset(modelCounters_, 0, MAX_CONTEXT_SIZE * comp->contextCount); 246 | u8* base = modelCounters_; 247 | for (int m = 0; m < comp->contextCount; ++m) { 248 | counters[m] = base; 249 | cp[m] = base; 250 | base += MAX_CONTEXT_SIZE; 251 | } 252 | 253 | u8* cout = (u8*)out; 254 | u32 x1 = 0, x2 = 0xffffffff; 255 | for (int j = 0; j < inLen; ++j) { 256 | u32 byte = *archive++; 257 | for (u32 i = 0; i < 8; ++i) { 258 | u32 n0 = 1, n1 = 1; 259 | for (int m = 0; m < comp->contextCount; ++m) { 260 | n0 += cp[m][0] * comp->weights[m]; 261 | n1 += cp[m][1] * comp->weights[m]; 262 | } 263 | 264 | u32 xmid = x1 + n0 * (u64)(x2 - x1) / (n0 + n1); 265 | 266 | int y; 267 | if (byte & 0x80) { 268 | x1 = xmid + 1; 269 | y = 1; 270 | } else { 271 | x2 = xmid; 272 | y = 0; 273 | } 274 | 275 | // Store bit y 276 | tbuf[0] += tbuf[0] + y; 277 | if (i == 7) { // Start new byte 278 | tbuf[7] = tbuf[6]; 279 | tbuf[6] = tbuf[5]; 280 | tbuf[5] = tbuf[4]; 281 | tbuf[4] = tbuf[3]; 282 | tbuf[3] = tbuf[2]; 283 | tbuf[2] = tbuf[1]; 284 | tbuf[1] = tbuf[0]; 285 | tbuf[0] = 1; 286 | } 287 | 288 | // Count y by context 289 | for (int m = comp->contextCount - 1; m >= 0; --m) { 290 | if (cp[m][y] < 255) 291 | ++cp[m][y]; 292 | if (cp[m][1-y] > 2) 293 | cp[m][1-y] = cp[m][1-y] / 2 + 1; 294 | u32 off = 0, cnt = 0; 295 | for (char i = 0; i < 8; ++i) { 296 | if (comp->contexts[m] & (1 << i)) { 297 | off = (off << 8) + tbuf[i]; 298 | } 299 | } 300 | // Use a sort of hashtable here. Decompressor just uses c = 0. 301 | u32 c = 24 * ((off & 0xffff) ^ (off >> 16)); 302 | while (*(u32*)&counters[m][c] != 0 && *(u32*)&counters[m][c] != off) c += 6; 303 | if (c > cmax) cmax = c; 304 | *(u32*)&counters[m][c] = off; 305 | cp[m] = &counters[m][c + 4]; 306 | } 307 | 308 | while (((x1 ^ x2) & 0xff000000) == 0) { 309 | *cout++ = x2 >> 24; 310 | x1 <<= 8; 311 | x2 = (x2 << 8) + 255; 312 | if (cout - (u8*)out >= *outLen) return false; 313 | } 314 | byte <<= 1; 315 | } 316 | } 317 | while (((x1 ^ x2) & 0xff000000)==0) { 318 | *cout++ = x2 >> 24; 319 | x1 <<= 8; 320 | x2 = (x2 << 8) + 255; 321 | if (cout - (u8*)out >= *outLen) return false; 322 | } 323 | *cout++ = x2 >> 24; // First unequal byte 324 | // Now for some weirdness: if the next byte happens to be less than 0xc3 (the 325 | // ret opcode), we need to output something that's less than that. Zero is a 326 | // good candidate. 327 | if (((x2 >> 16) & 0xff) < 0xc3) { 328 | if (cout - (u8*)out >= *outLen) return false; 329 | *cout++ = 0; 330 | } 331 | *outLen = cout - (u8*)out; 332 | return true; 333 | } 334 | 335 | -------------------------------------------------------------------------------- /pack.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | #ifndef INCLUDED_PACK_H 18 | #define INCLUDED_PACK_H 19 | 20 | #define MAX_CONTEXT_COUNT 16 21 | #define MAX_CONTEXT_SIZE (4 << 20) 22 | 23 | typedef unsigned char u8; 24 | typedef unsigned short u16; 25 | typedef unsigned int u32; 26 | typedef unsigned long long u64; 27 | 28 | struct CompressionParameters { 29 | int contextCount = 0; 30 | u8 weights[MAX_CONTEXT_COUNT]; 31 | u8 contexts[MAX_CONTEXT_COUNT]; 32 | 33 | bool FromString(const char* str); 34 | void ToString(char* str); 35 | }; 36 | 37 | class Compressor { 38 | public: 39 | //! Compresses data. 40 | /*! \param params Filled out with the compression parameters. 41 | \param in Pointer to input data. 42 | \param inLen Length of input data in bytes. 43 | \param out Pointer to output data. 44 | \param outLen Pointer to length of output data. Must contain maximum length of output data as input. 45 | \return true if the data could be compressed into the provided output buffer. 46 | */ 47 | bool Compress(CompressionParameters* params, void* in, int inLen, void* out, int* outLen); 48 | 49 | //! Decompresses data. 50 | /*! \param params Compression parameters. 51 | \param in Pointer to last 4 bytes of input data, since this is read backwards. 52 | \param out Pointer to output data. 53 | \param outLen Length of output data. 54 | */ 55 | void Decompress(CompressionParameters* params, void* in, void* out, int outLen); 56 | 57 | private: 58 | bool CompressSingle(CompressionParameters* comp, void* in, int inLen, void* out, int* outLen); 59 | 60 | private: 61 | unsigned char modelCounters_[MAX_CONTEXT_SIZE * MAX_CONTEXT_COUNT]; 62 | bool verbose_ = false; 63 | }; 64 | 65 | #endif // INCLUDED_PACK_H 66 | -------------------------------------------------------------------------------- /packer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "pack.h" 26 | 27 | typedef unsigned char u8; 28 | typedef unsigned short u16; 29 | typedef unsigned int u32; 30 | typedef unsigned long long u64; 31 | typedef unsigned int u24; 32 | 33 | void Invert(u8* data, u32 s) { 34 | for (u32 i = 0; i < s >> 1; ++i) { 35 | u8 t = data[i]; 36 | data[i] = data[s - i - 1]; 37 | data[s - i - 1] = t; 38 | } 39 | } 40 | 41 | int main(int argc, char*argv[]) { 42 | if (argc < 2) { return 1; } 43 | bool unpack = strstr(argv[1], ".pack") != nullptr; 44 | FILE* fptr = fopen(argv[1], "rb"); 45 | if (!fptr) { printf("Could not open %s\n", argv[1]); return 1; } 46 | fseek(fptr, 0, SEEK_END); 47 | u32 size = ftell(fptr); 48 | fseek(fptr, 0, SEEK_SET); 49 | int os = 0; 50 | CompressionParameters params; 51 | memset(¶ms, 0, sizeof(params)); 52 | if (unpack) { 53 | fread(&os, 4, 1, fptr); 54 | fread(¶ms.contextCount, 1, 1, fptr); 55 | fread(params.weights, params.contextCount, 1, fptr); 56 | fread(params.contexts, params.contextCount, 1, fptr); 57 | size -= ftell(fptr); 58 | } 59 | u8* data = (u8*)malloc(size + 10); 60 | memset(data, 0, size + 10); 61 | data += 10; // Ugly, but we can ensure we have a few zero bytes at the beginning of the input. 62 | fread(data, 1, size, fptr); 63 | fclose(fptr); 64 | 65 | char ofn[256]; 66 | strcpy(ofn, argv[1]); 67 | if (unpack) { 68 | *strrchr(ofn, '.') = 0; 69 | strcat(ofn, ".unpack"); 70 | } else { 71 | strcat(ofn, ".pack"); 72 | } 73 | 74 | u8* out = (u8*)malloc(65536); 75 | memset(out, 0, 65536); 76 | out += 10; // Ugly, but we can ensure we have a few zero bytes at the beginning of the output. 77 | FILE* ofptr = fopen(ofn, "wb"); 78 | if (!ofptr) { printf("Could not open %s\n", argv[1]); return 1; } 79 | 80 | if (unpack) { 81 | Compressor* comp = new Compressor(); 82 | comp->Decompress(¶ms, &data[size - 4], out, os); 83 | fwrite(out, os, 1, ofptr); 84 | } else { 85 | Compressor* comp = new Compressor(); 86 | os = 65528; 87 | comp->Compress(¶ms, data, size, out, &os); 88 | Invert(out, os); 89 | 90 | fwrite(&size, 4, 1, ofptr); 91 | fwrite(¶ms.contextCount, 1, 1, ofptr); 92 | fwrite(params.weights, params.contextCount, 1, ofptr); 93 | fwrite(params.contexts, params.contextCount, 1, ofptr); 94 | fwrite(out, os, 1, ofptr); 95 | } 96 | fclose(ofptr); 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /prt.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | #include 18 | 19 | int a = 5; 20 | int b = 0; 21 | int c[4096]; 22 | 23 | void HexDump(const void* data, int length) { 24 | int i, j; 25 | for (i = 0; i < length; i += 16) { 26 | printf("%8x | ", i); 27 | for (j = 0; j < 16; ++j) { 28 | if (i + j < length) { 29 | printf("%2.2x ", ((unsigned char*)data)[i + j]); 30 | } else { 31 | printf(" "); 32 | } 33 | } 34 | printf("| "); 35 | for (j = 0; j < 16; ++j) { 36 | if (i + j < length) { 37 | unsigned char c = ((unsigned char*)data)[i + j]; 38 | // For some reason 127 is also a control char ^? 39 | printf("%c", (c >= 32 && c < 127) ? c : '.'); 40 | } else { 41 | printf(" "); 42 | } 43 | } 44 | printf(" |\n"); 45 | } 46 | } 47 | 48 | void _start() { 49 | puts("Hello"); 50 | printf("_start: %p\n", _start); 51 | printf("a: %p %d\n", &a, a); 52 | printf("b: %p %d\n", &b, b); 53 | printf("c: %p %d\n", c, c[0]); 54 | //HexDump((void*)0x08010000, 1024); 55 | __asm ("mov $1, %eax\n" 56 | "mov %eax, %ebx\n" 57 | "int $0x80"); 58 | } 59 | -------------------------------------------------------------------------------- /unpack.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // elfling - a linking compressor for ELF files by Minas ^ Calodox 16 | 17 | #include "pack.h" 18 | 19 | #include 20 | #include 21 | 22 | void Compressor::Decompress(CompressionParameters* params, void* in, void* out, int outLen) { 23 | u8* counters[MAX_CONTEXT_COUNT]; // Counter base offsets 24 | u8* cp[MAX_CONTEXT_COUNT]; // Current counters 25 | u8* archive = (u8*)in; 26 | u8* cout = (u8*)out; 27 | 28 | memset(modelCounters_, 0, MAX_CONTEXT_SIZE * params->contextCount); 29 | u8* base = modelCounters_; 30 | for (int m = 0; m < params->contextCount; ++m) { 31 | counters[m] = base; 32 | cp[m] = base; 33 | base += MAX_CONTEXT_SIZE; 34 | } 35 | 36 | *cout = 1; 37 | u32 x1 = 0, x2 = 0xffffffff; 38 | for (u32 j = outLen * 8; j > 0; --j) { 39 | u32 n0 = 1, n1 = 1; 40 | for (char m = 0; m < params->contextCount; ++m) { 41 | n0 += cp[m][0] * params->weights[m]; 42 | n1 += cp[m][1] * params->weights[m]; 43 | } 44 | 45 | u32 xmid = x1 + n0 * (u64)(x2 - x1) / (n0 + n1); 46 | 47 | char y; 48 | cout[0] <<= 1; 49 | if (*(u32*)archive <= xmid) { 50 | x2 = xmid; 51 | y = 0; 52 | } else { 53 | cout[0] += 1; 54 | x1 = xmid + 1; 55 | y = 1; 56 | } 57 | 58 | if (((j - 1) & 7) == 0) { // Start new byte 59 | cout++; 60 | *cout = 1; 61 | } 62 | 63 | // Count y by context 64 | for (char m = 0; m < params->contextCount; ++m) { 65 | if (cp[m][y] < 255) 66 | ++cp[m][y]; 67 | if (cp[m][1 - y] > 2) 68 | cp[m][1 - y] = cp[m][1 - y] / 2 + 1; 69 | u32 off = 0, cnt = 0; 70 | for (char i = 0; i < 8; ++i) { 71 | if (params->contexts[m] & (1 << i)) { 72 | off = (off << 8) + cout[-i]; 73 | } 74 | } 75 | u32 c = 0; 76 | while (*(u32*)&counters[m][c] != 0 && *(u32*)&counters[m][c] != off) c += 6; 77 | *(u32*)&counters[m][c] = off; 78 | cp[m] = &counters[m][c + 4]; 79 | } 80 | 81 | while (((x1 ^ x2) >> 24) == 0) { 82 | x1 <<= 8; 83 | x2 = (x2 << 8) + 255; 84 | --archive; 85 | } 86 | } 87 | } 88 | 89 | --------------------------------------------------------------------------------