/* simple-object-coff.c -- routines to manipulate COFF object files.
Copyright (C) 2010-2024 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
struct simple_object_coff_read
{
/* Magic number. */
unsigned short magic;
/* Whether the file is big-endian. */
unsigned char is_big_endian;
/* Number of sections. */
unsigned short nscns;
/* File offset of symbol table. */
off_t symptr;
/* Number of symbol table entries. */
unsigned int nsyms;
/* Flags. */
unsigned short flags;
/* Offset of section headers in file. */
off_t scnhdr_offset;
};
/* Private data for an simple_object_attributes. */
struct simple_object_coff_attributes
{
/* Magic number. */
unsigned short magic;
/* Whether the file is big-endian. */
unsigned char is_big_endian;
/* Flags. */
unsigned short flags;
};
/* There is no magic number which indicates a COFF file as opposed to
any other sort of file. Instead, each COFF file starts with a
two-byte magic number which also indicates the type of the target.
This struct holds a magic number as well as characteristics of that
COFF format. */
struct coff_magic_struct
{
/* Magic number. */
unsigned short magic;
/* Whether this magic number is for a big-endian file. */
unsigned char is_big_endian;
/* Flag bits, in the f_flags fields, which indicates that this file
is not a relocatable object file. There is no flag which
specifically indicates a relocatable object file, it is only
implied by the absence of these flags. */
unsigned short non_object_flags;
};
/* This is a list of the COFF magic numbers which we recognize, namely
the ones used on Windows. More can be added as needed. */
strindex = strtol (namebuf + 1, &end, 10);
if (*end == '\0')
{
/* The real section name is found in the string
table. */
if (strtab == NULL)
{
strtab = simple_object_coff_read_strtab (sobj,
&strtab_size,
&errmsg, err);
if (strtab == NULL)
{
XDELETEVEC (scnbuf);
return errmsg;
}
}
if (strindex < 4 || strindex >= strtab_size)
{
XDELETEVEC (strtab);
XDELETEVEC (scnbuf);
*err = 0;
return "section string index out of range";
}
/* We're just going to record the attributes, but we need to make a
copy because the user may delete them. */
ret = XNEW (struct simple_object_coff_attributes);
*ret = *attrs;
return ret;
}
static const char *
simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor,
int *err)
{
struct simple_object_coff_attributes *attrs =
(struct simple_object_coff_attributes *) sobj->data;
unsigned int nscns, secnum;
simple_object_write_section *section;
off_t scnhdr_offset;
size_t symtab_offset;
off_t secsym_offset;
unsigned int nsyms;
size_t offset;
size_t name_offset;
const char *errmsg;
unsigned char strsizebuf[4];
/* The interface doesn't give us access to the name of the input file
yet. We want to use its basename for the FILE symbol. This is
what 'gas' uses when told to assemble from stdin. */
const char *source_filename = "fake";
size_t sflen;
union
{
struct external_syment sym;
union external_auxent aux;
} syms[2];
void (*set_16) (unsigned char *, unsigned short);
void (*set_32) (unsigned char *, unsigned int);
/* Symbol table is always half-word aligned. */
offset += (offset & 1);
/* There is a file symbol and a section symbol per section,
and each of these has a single auxiliary symbol following. */
nsyms = 2 * (nscns + 1);
symtab_offset = offset;
/* Advance across space reserved for symbol table to locate
start of string table. */
offset += nsyms * sizeof (struct external_syment);
/* Write out file symbol. */
memset (&syms[0], 0, sizeof (syms));
strcpy ((char *)&syms[0].sym.e.e_name[0], ".file");
set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG);
set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE;
syms[0].sym.e_numaux[0] = 1;
/* The name need not be nul-terminated if it fits into the x_fname field
directly, but must be if it has to be placed into the string table. */
sflen = strlen (source_filename);
if (sflen <= E_FILNMLEN)
memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
else
{
set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset);
if (!simple_object_internal_write (descriptor, offset + name_offset,
((const unsigned char *)
source_filename),
sflen + 1, &errmsg, err))
return errmsg;
name_offset += strlen (source_filename) + 1;
}
if (!simple_object_internal_write (descriptor, symtab_offset,
(const unsigned char *) &syms[0],
sizeof (syms), &errmsg, err))
return errmsg;
/* Write the string table length, followed by the strings and section
symbols in step with each other. */
set_32 (strsizebuf, name_offset);
if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
&errmsg, err))
return errmsg;