+/* Set up PE subsystem. */
+
+static void
+set_pe_subsystem (const char *s)
+{
+ const char *version, *subsystem;
+ size_t i;
+ static const struct
+ {
+ const char *name;
+ const char set_def;
+ const short value;
+ }
+ v[] =
+ {
+ { "native", 0, IMAGE_SUBSYSTEM_NATIVE },
+ { "windows", 0, IMAGE_SUBSYSTEM_WINDOWS_GUI },
+ { "console", 0, IMAGE_SUBSYSTEM_WINDOWS_CUI },
+ { "posix", 0, IMAGE_SUBSYSTEM_POSIX_CUI },
+ { "wince", 0, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI },
+ { "efi-app", 1, IMAGE_SUBSYSTEM_EFI_APPLICATION },
+ { "efi-bsd", 1, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER },
+ { "efi-rtd", 1, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER },
+ { "sal-rtd", 1, IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER },
+ { "xbox", 0, IMAGE_SUBSYSTEM_XBOX }
+ };
+ short value;
+ char *copy;
+ int set_def = -1;
+
+ /* Check for the presence of a version number. */
+ version = strchr (s, ':');
+ if (version == NULL)
+ subsystem = s;
+ else
+ {
+ int len = version - s;
+ copy = xstrdup (s);
+ subsystem = copy;
+ copy[len] = '\0';
+ version = copy + 1 + len;
+ pe_major_subsystem_version = strtoul (version, ©, 0);
+ if (*copy == '.')
+ pe_minor_subsystem_version = strtoul (copy + 1, ©, 0);
+ if (*copy != '\0')
+ non_fatal (_("%s: bad version in PE subsystem"), s);
+ }
+
+ /* Check for numeric subsystem. */
+ value = (short) strtol (subsystem, ©, 0);
+ if (*copy == '\0')
+ {
+ for (i = 0; i < ARRAY_SIZE (v); i++)
+ if (v[i].value == value)
+ {
+ pe_subsystem = value;
+ set_def = v[i].set_def;
+ break;
+ }
+ }
+ else
+ {
+ /* Search for subsystem by name. */
+ for (i = 0; i < ARRAY_SIZE (v); i++)
+ if (strcmp (subsystem, v[i].name) == 0)
+ {
+ pe_subsystem = v[i].value;
+ set_def = v[i].set_def;
+ break;
+ }
+ }
+
+ switch (set_def)
+ {
+ case -1:
+ fatal (_("unknown PE subsystem: %s"), s);
+ break;
+ case 0:
+ break;
+ default:
+ if (pe_file_alignment == (bfd_vma) -1)
+ pe_file_alignment = PE_DEF_FILE_ALIGNMENT;
+ if (pe_section_alignment == (bfd_vma) -1)
+ pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
+ break;
+ }
+ if (s != subsystem)
+ free ((char *) subsystem);
+}
+
+/* Convert EFI target to PEI target. */
+
+static void
+convert_efi_target (char *efi)
+{
+ efi[0] = 'p';
+ efi[1] = 'e';
+ efi[2] = 'i';
+
+ if (strcmp (efi + 4, "ia32") == 0)
+ {
+ /* Change ia32 to i386. */
+ efi[5]= '3';
+ efi[6]= '8';
+ efi[7]= '6';
+ }
+ else if (strcmp (efi + 4, "x86_64") == 0)
+ {
+ /* Change x86_64 to x86-64. */
+ efi[7] = '-';
+ }
+}
+
+/* Allocate and return a pointer to a struct section_add, initializing the
+ structure using ARG, a string in the format "sectionname=filename".
+ The returned structure will have its next pointer set to NEXT. The
+ OPTION field is the name of the command line option currently being
+ parsed, and is only used if an error needs to be reported. */
+
+static struct section_add *
+init_section_add (const char *arg,
+ struct section_add *next,
+ const char *option)
+{
+ struct section_add *pa;
+ const char *s;
+
+ s = strchr (arg, '=');
+ if (s == NULL)
+ fatal (_("bad format for %s"), option);
+
+ pa = (struct section_add *) xmalloc (sizeof (struct section_add));
+ pa->name = xstrndup (arg, s - arg);
+ pa->filename = s + 1;
+ pa->next = next;
+ pa->contents = NULL;
+ pa->size = 0;
+
+ return pa;
+}
+
+/* Load the file specified in PA, allocating memory to hold the file
+ contents, and store a pointer to the allocated memory in the contents
+ field of PA. The size field of PA is also updated. All errors call
+ FATAL. */
+
+static void
+section_add_load_file (struct section_add *pa)
+{
+ size_t off, alloc;
+ FILE *f;
+
+ /* We don't use get_file_size so that we can do
+ --add-section .note.GNU_stack=/dev/null
+ get_file_size doesn't work on /dev/null. */
+
+ f = fopen (pa->filename, FOPEN_RB);
+ if (f == NULL)
+ fatal (_("cannot open: %s: %s"),
+ pa->filename, strerror (errno));
+
+ off = 0;
+ alloc = 4096;
+ pa->contents = (bfd_byte *) xmalloc (alloc);
+ while (!feof (f))
+ {
+ off_t got;
+
+ if (off == alloc)
+ {
+ alloc <<= 1;
+ pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
+ }
+
+ got = fread (pa->contents + off, 1, alloc - off, f);
+ if (ferror (f))
+ fatal (_("%s: fread failed"), pa->filename);
+
+ off += got;
+ }
+
+ pa->size = off;
+
+ fclose (f);
+}
+