1/* Copyright (C) 2019-2020 Free Software Foundation, Inc. 2 3 This file is part of GNU Binutils. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 18 02110-1301, USA. */ 19 20 21/* This file generates a number of DLL (PE/COFF binaries traditionally 22 used on Windows) that we can then utilize in various tests to 23 ensure objdump can parse these file correctly. 24 25 See: 26 https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf */ 27 28#include <memory.h> 29#include <stdint.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <unistd.h> 34 35#define INCORRECT_USAGE 2 36#define IO_ERROR 3 37 38static void 39write_dos_header_and_stub (FILE* file) 40{ 41 /* See ECMA-335 II.25.2.1. 42 Instead of lfanew, lets just hardcode the offset of the next byte 43 after this header (0x80). */ 44 char buffer[128] = 45 { 46 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 47 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 48 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* Last 4 bytes are precomputed lfanew. */ 54 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 55 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, 56 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 57 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 58 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 59 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 60 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 61 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 62 }; 63 64 fwrite (buffer, 1, 128, file); 65} 66 67static void 68write_pe_signature (FILE* file) 69{ 70 char buffer[4]; 71 72 buffer[0] = 'P'; 73 buffer[1] = 'E'; 74 buffer[2] = 0; 75 buffer[3] = 0; 76 fwrite (buffer, 1, 4, file); 77} 78 79static void 80write_coff_header (FILE* file, uint16_t machine) 81{ 82 char buffer[128]; 83 84 memset (buffer, 0, sizeof (buffer)); 85 86 /* Machine. ECMA-335 says this must be 0x14c but that's not true anymore. */ 87 buffer[0] = machine & 0xff; 88 buffer[1] = machine >> 0x8; 89 fwrite (buffer, 2, 1, file); 90 memset (buffer, 0, sizeof (buffer)); 91 /* NumberOfSections = 0. */ 92 fwrite (buffer, 2, 1, file); 93 /* TimeDateStamp = 0. */ 94 fwrite (buffer, 4, 1, file); 95 /* PointerToSymbolTable = 0. */ 96 fwrite (buffer, 4, 1, file); 97 /* NumberOfSymbols = 0. */ 98 fwrite (buffer, 4, 1, file); 99 /* OptionalHeaderSize = 0. */ 100 fwrite (buffer, 2, 1, file); 101 /* Characteristics = 0x2000. */ 102 buffer[0] = 0x00; 103 buffer[1] = 0x20; 104 fwrite (buffer, 2, 1, file); 105 memset (buffer, 0 , sizeof (buffer)); 106} 107 108static void 109write_simple_dll (const char* name, uint16_t machine) 110{ 111 FILE* file = fopen (name, "w"); 112 113 if (file == NULL) 114 { 115 fprintf (stderr, "error: unable to open file for writing\n"); 116 exit (IO_ERROR); 117 } 118 119 write_dos_header_and_stub (file); 120 write_pe_signature (file); 121 write_coff_header (file, machine); 122 fclose (file); 123 file = NULL; 124 printf ("wrote %s\n", name); 125} 126 127int 128main (int argc, char** argv) 129{ 130 char* program_name = argv[0]; 131 char* output_directory = argv[1]; 132 int i; 133 134 if (argc < 3) 135 { 136 fprintf (stderr, "usage: %s output-directory format [format ...] \n\n", program_name); 137 fprintf (stderr, "format is an objdump-style format string, like pei-i386\n"); 138 exit (INCORRECT_USAGE); 139 } 140 141 if (chdir (output_directory) != 0) 142 { 143 fprintf (stderr, "error: unable to change directory to %s\n", output_directory); 144 exit (INCORRECT_USAGE); 145 } 146 147 /* We generate a simple PEI format files, and then .NET Core on 148 Linux-style PEI files for a number of architectures. As opposed 149 to the more common PEI files that contain bytecode (CIL/MSIL), many 150 .NET Core DLLs are pre-compiled for specific architectures and 151 platforms. See https://github.com/jbevain/cecil/issues/337 for an 152 example of this value being used in practice. */ 153 154 for (i = 2; i < argc; i++) 155 { 156 char* wanted_format = argv[i]; 157 158 if (strcmp ("pei-i386", wanted_format) == 0) 159 { 160 write_simple_dll ("simple-pei-i386.dll", 0x14c); 161 162 write_simple_dll ("linux-pei-i386.dll", 0x14c ^ 0x7b79 /* i386 + Linux */); 163 } 164 else if (strcmp ("pei-x86-64", wanted_format) == 0) 165 { 166 write_simple_dll ("simple-pei-x86-64.dll", 0x8664); 167 168 write_simple_dll ("linux-pei-x86-64.dll", 0x8664 ^ 0x7b79 /* x86-64 + Linux */); 169 } 170 else 171 { 172 fprintf (stderr, "error: can't handle format %s\n", wanted_format); 173 exit (INCORRECT_USAGE); 174 } 175 } 176 177 return 0; 178} 179