(root)/
binutils-2.41/
binutils/
testsuite/
gentestdlls.c
       1  /* Copyright (C) 2019-2023 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  
      38  static void
      39  write_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  
      67  static void
      68  write_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  
      79  static void
      80  write_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  
     108  static void
     109  write_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  
     127  int
     128  main (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  }