merge from gcc

This commit is contained in:
DJ Delorie 2010-11-02 15:20:47 +00:00
parent 877791769e
commit ffa54e5c48
14 changed files with 4152 additions and 5 deletions

View File

@ -1,3 +1,7 @@
2010-11-02 Ian Lance Taylor <iant@google.com>
* simple-object.h: New file.
2010-10-15 Dave Korn <dave.korn.cygwin@gmail.com>
Sync LD plugin patch series (part 1/6) with src/include/.

203
include/simple-object.h Normal file
View File

@ -0,0 +1,203 @@
/* simple-object.h -- simple routines to read and write object files
Copyright 2010 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. */
#ifndef SIMPLE_OBJECT_H
#define SIMPLE_OBJECT_H
#include <stddef.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* This header file provides four types with associated functions.
They are used to read and write object files. This is a minimal
interface, intended to support the needs of gcc without bringing in
all the power and complexity of BFD. */
/* The type simple_object_read * is used to read an existing object
file. */
typedef struct simple_object_read_struct simple_object_read;
/* Create an simple_object_read given DESCRIPTOR, an open file
descriptor, and OFFSET, an offset within the file. The offset is
for use with archives, and should be 0 for an ordinary object file.
The descriptor must remain open until done with the returned
simple_object_read. SEGMENT_NAME is used on Mach-O and is required
on that platform: it means to only look at sections within the
segment with that name. It is ignored for other object file
formats. On error, this function returns NULL, and sets *ERRMSG to
an error string and sets *ERR to an errno value or 0 if there is no
relevant errno. */
extern simple_object_read *
simple_object_start_read (int descriptor, off_t offset,
const char *segment_name, const char **errmsg,
int *err);
/* Call PFN for each section in SIMPLE_OBJECT, passing it the section
name, offset within the file of the section contents, and length of
the section contents. The offset within the file is relative to
the offset passed to simple_object_start_read. The DATA argument
to simple_object_find_sections is passed on to PFN. If PFN returns
0, the loop is stopped and simple_object_find_sections returns. If
PFN returns non-zero, the loop continues. On success this returns
NULL. On error it returns an error string, and sets *ERR to an
errno value or 0 if there is no relevant errno. */
extern const char *
simple_object_find_sections (simple_object_read *simple_object,
int (*pfn) (void *data, const char *,
off_t offset, off_t length),
void *data,
int *err);
/* Look for the section NAME in SIMPLE_OBJECT. This returns
information for the first section NAME in SIMPLE_OBJECT. Note that
calling this multiple times is inefficient; use
simple_object_find_sections instead.
If found, return 1 and set *OFFSET to the offset in the file of the
section contents and set *LENGTH to the length of the section
contents. *OFFSET will be relative to the offset passed to
simple_object_start_read.
If the section is not found, and no error occurs, return 0 and set
*ERRMSG to NULL.
If an error occurs, return 0, set *ERRMSG to an error message, and
set *ERR to an errno value or 0 if there is no relevant errno. */
extern int
simple_object_find_section (simple_object_read *simple_object,
const char *name, off_t *offset, off_t *length,
const char **errmsg, int *err);
/* Release all resources associated with SIMPLE_OBJECT. This does not
close the file descriptor. */
extern void
simple_object_release_read (simple_object_read *);
/* The type simple_object_attributes holds the attributes of an object
file that matter for creating a file or ensuring that two files are
compatible. This is a set of magic numbers. */
typedef struct simple_object_attributes_struct simple_object_attributes;
/* Fetch the attributes of SIMPLE_OBJECT. This information will
persist until simple_object_attributes_release is called, even if
SIMPLE_OBJECT is closed. On error this returns NULL, sets *ERRMSG
to an error message, and sets *ERR to an errno value or 0 if there
isn't one. */
extern simple_object_attributes *
simple_object_fetch_attributes (simple_object_read *simple_object,
const char **errmsg, int *err);
/* Compare ATTRS1 and ATTRS2. If they could be linked together
without error, return NULL. Otherwise, return an error message,
set *ERR to an errno value or 0 if there isn't one. */
extern const char *
simple_object_attributes_compare (simple_object_attributes *attrs1,
simple_object_attributes *attrs2,
int *err);
/* Release all resources associated with ATTRS. */
extern void
simple_object_release_attributes (simple_object_attributes *attrs);
/* The type simple_object_write is used to create a new object file. */
typedef struct simple_object_write_struct simple_object_write;
/* Start creating a new object file which is like ATTRS. You must
fetch attribute information from an existing object file before you
can create a new one. There is currently no support for creating
an object file de novo. The segment name is only used on Mach-O,
where it is required. It means that all sections are created
within that segment. It is ignored for other object file formats.
On error this function returns NULL, sets *ERRMSG to an error
message, and sets *ERR to an errno value or 0 if there isn't
one. */
extern simple_object_write *
simple_object_start_write (simple_object_attributes *attrs,
const char *segment_name,
const char **errmsg, int *err);
/* The type simple_object_write_section is a handle for a section
which is being written. */
typedef struct simple_object_write_section_struct simple_object_write_section;
/* Add a section to SIMPLE_OBJECT. NAME is the name of the new
section. ALIGN is the required alignment expressed as the number
of required low-order 0 bits (e.g., 2 for alignment to a 32-bit
boundary). The section is created as containing data, readable,
not writable, not executable, not loaded at runtime. On error this
returns NULL, sets *ERRMSG to an error message, and sets *ERR to an
errno value or 0 if there isn't one. */
extern simple_object_write_section *
simple_object_write_create_section (simple_object_write *simple_object,
const char *name, unsigned int align,
const char **errmsg, int *err);
/* Add data BUFFER/SIZE to SECTION in SIMPLE_OBJECT. If COPY is
non-zero, the data will be copied into memory if necessary. If
COPY is zero, BUFFER must persist until SIMPLE_OBJECT is released.
On success this returns NULL. On error this returns an error
message, and sets *ERR to an errno value or 0 if there isn't
one. */
extern const char *
simple_object_write_add_data (simple_object_write *simple_object,
simple_object_write_section *section,
const void *buffer, size_t size,
int copy, int *err);
/* Write the complete object file to DESCRIPTOR, an open file
descriptor. This returns NULL on success. On error this returns
an error message, and sets *ERR to an errno value or 0 if there
isn't one. */
extern const char *
simple_object_write_to_file (simple_object_write *simple_object,
int descriptor, int *err);
/* Release all resources associated with SIMPLE_OBJECT, including any
simple_object_write_section's that may have been created. */
extern void
simple_object_release_write (simple_object_write *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,3 +1,22 @@
2010-11-02 Ian Lance Taylor <iant@google.com>
Dave Korn <dave.korn.cygwin@gmail.com>
Iain Sandoe <iains@gcc.gnu.org>
* simple-object.c: New file.
* simple-object-common.h: New file.
* simple-object-elf.c: New file.
* simple-object-mach-o.c: New file.
* simple-object-coff.c: New file.
* simple-object.txh: New file.
* configure.ac: Add AC_TYPE_SSIZE_T.
* Makefile.in: Rebuild dependencies.
(CFILES): Add simple-object.c, simple-object-coff,
simple-object-elf.c, and simple-object-mach-o.c.
(REQUIRED_OFILES): Add corresponding object files.
* configure: Rebuild.
* config.in: Rebuild.
* functions.texi: Rebuild.
2010-10-29 Ian Lance Taylor <iant@google.com>
* setproctitle.c: Add space after function name in @deftypefn

View File

@ -2,8 +2,8 @@
# Originally written by K. Richard Pixley <rich@cygnus.com>.
#
# Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
# Foundation
# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
# Free Software Foundation
#
# This file is part of the libiberty library.
# Libiberty is free software; you can redistribute it and/or
@ -145,6 +145,8 @@ CFILES = alloca.c argv.c asprintf.c atexit.c \
physmem.c putenv.c \
random.c regex.c rename.c rindex.c \
safe-ctype.c setenv.c setproctitle.c sha1.c sigsetmask.c \
simple-object.c simple-object-coff.c simple-object-elf.c \
simple-object-mach-o.c \
snprintf.c sort.c \
spaces.c splay-tree.c stpcpy.c stpncpy.c strcasecmp.c \
strchr.c strdup.c strerror.c strncasecmp.c strncmp.c \
@ -172,11 +174,15 @@ REQUIRED_OFILES = \
./getruntime.$(objext) ./hashtab.$(objext) ./hex.$(objext) \
./lbasename.$(objext) ./lrealpath.$(objext) \
./make-relative-prefix.$(objext) ./make-temp-file.$(objext) \
./objalloc.$(objext) ./obstack.$(objext) \
./objalloc.$(objext) \
./obstack.$(objext) \
./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext) \
./pex-common.$(objext) ./pex-one.$(objext) \
./@pexecute@.$(objext) \
./safe-ctype.$(objext) ./sort.$(objext) ./spaces.$(objext) \
./safe-ctype.$(objext) \
./simple-object.$(objext) ./simple-object-coff.$(objext) \
./simple-object-elf.$(objext) ./simple-object-mach-o.$(objext) \
./sort.$(objext) ./spaces.$(objext) \
./splay-tree.$(objext) ./strerror.$(objext) \
./strsignal.$(objext) ./unlink-if-ordinary.$(objext) \
./xatexit.$(objext) ./xexit.$(objext) ./xmalloc.$(objext) \
@ -312,7 +318,7 @@ TEXISRC = \
# Additional files that have texi snippets that need to be collected
# and sorted. Some are here because the sources are imported from
# elsewhere. Others represent headers in ../include.
TEXIFILES = fnmatch.txh pexecute.txh
TEXIFILES = fnmatch.txh pexecute.txh simple-object.txh
libiberty.info : $(srcdir)/libiberty.texi $(TEXISRC)
$(MAKEINFO) -I$(srcdir) $(srcdir)/libiberty.texi
@ -965,6 +971,38 @@ $(CONFIGURED_OFILES): stamp-picdir
else true; fi
$(COMPILE.c) $(srcdir)/sigsetmask.c $(OUTPUT_OPTION)
./simple-object-coff.$(objext): $(srcdir)/simple-object-coff.c config.h \
$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
$(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h
if [ x"$(PICFLAG)" != x ]; then \
$(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-coff.c -o pic/$@; \
else true; fi
$(COMPILE.c) $(srcdir)/simple-object-coff.c $(OUTPUT_OPTION)
./simple-object-elf.$(objext): $(srcdir)/simple-object-elf.c config.h \
$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
$(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h
if [ x"$(PICFLAG)" != x ]; then \
$(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-elf.c -o pic/$@; \
else true; fi
$(COMPILE.c) $(srcdir)/simple-object-elf.c $(OUTPUT_OPTION)
./simple-object-mach-o.$(objext): $(srcdir)/simple-object-mach-o.c config.h \
$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
$(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h
if [ x"$(PICFLAG)" != x ]; then \
$(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object-mach-o.c -o pic/$@; \
else true; fi
$(COMPILE.c) $(srcdir)/simple-object-mach-o.c $(OUTPUT_OPTION)
./simple-object.$(objext): $(srcdir)/simple-object.c config.h \
$(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
$(srcdir)/simple-object-common.h $(INCDIR)/simple-object.h
if [ x"$(PICFLAG)" != x ]; then \
$(COMPILE.c) $(PICFLAG) $(srcdir)/simple-object.c -o pic/$@; \
else true; fi
$(COMPILE.c) $(srcdir)/simple-object.c $(OUTPUT_OPTION)
./snprintf.$(objext): $(srcdir)/snprintf.c $(INCDIR)/ansidecl.h
if [ x"$(PICFLAG)" != x ]; then \
$(COMPILE.c) $(PICFLAG) $(srcdir)/snprintf.c -o pic/$@; \

View File

@ -467,6 +467,9 @@
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to `int' if <sys/types.h> does not define. */
#undef ssize_t
/* Define to the type of an unsigned integer type wide enough to hold a
pointer, if such a type exists, and if the system does not define it. */
#undef uintptr_t

11
libiberty/configure vendored
View File

@ -5203,6 +5203,17 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default"
if test "x$ac_cv_type_ssize_t" = x""yes; then :
else
cat >>confdefs.h <<_ACEOF
#define ssize_t int
_ACEOF
fi
# Given the above check, we always have uintptr_t or a fallback
# definition. So define HAVE_UINTPTR_T in case any imported code

View File

@ -290,6 +290,7 @@ fi
AC_TYPE_INTPTR_T
AC_TYPE_UINTPTR_T
AC_TYPE_SSIZE_T
# Given the above check, we always have uintptr_t or a fallback
# definition. So define HAVE_UINTPTR_T in case any imported code

View File

@ -1181,6 +1181,186 @@ be the value @code{1}).
@end deftypefn
@c simple-object.txh:87
@deftypefn Extension {const char *} simple_object_attributes_compare (simple_object_attributes *@var{attrs1}, simple_object_attributes *@var{attrs2}, int *@var{err})
Compare @var{attrs1} and @var{attrs2}. If they could be linked
together without error, return @code{NULL}. Otherwise, return an
error message and set @code{*@var{err}} to an errno value or @code{0}
if there is no relevant errno.
@end deftypefn
@c simple-object.txh:73
@deftypefn Extension {simple_object_attributes *} simple_object_fetch_attributes (simple_object_read *@var{simple_object}, const char **@var{errmsg}, int *@var{err})
Fetch the attributes of @var{simple_object}. The attributes are
internal information such as the format of the object file, or the
architecture it was compiled for. This information will persist until
@code{simple_object_attributes_release} is called, even if
@var{simple_object} itself is released.
On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an
error message, and sets @code{*@var{err}} to an errno value or
@code{0} if there is no relevant errno.
@end deftypefn
@c simple-object.txh:44
@deftypefn Extension {int} simple_object_find_section (simple_object_read *@var{simple_object} off_t *@var{offset}, off_t *@var{length}, const char **@var{errmsg}, int *@var{err})
Look for the section @var{name} in @var{simple_object}. This returns
information for the first section with that name.
If found, return 1 and set @code{*@var{offset}} to the offset in the
file of the section contents and set @code{*@var{length}} to the
length of the section contents. The value in @code{*@var{offset}}
will be relative to the offset passed to
@code{simple_object_open_read}.
If the section is not found, and no error occurs,
@code{simple_object_find_section} returns @code{0} and set
@code{*@var{errmsg}} to @code{NULL}.
If an error occurs, @code{simple_object_find_section} returns
@code{0}, sets @code{*@var{errmsg}} to an error message, and sets
@code{*@var{err}} to an errno value or @code{0} if there is no
relevant errno.
@end deftypefn
@c simple-object.txh:25
@deftypefn Extension {const char *} simple_object_find_sections (simple_object_read *@var{simple_object}, int (*@var{pfn}) (void *@var{data}, const char *@var{name}, off_t @var{offset}, off_t @var{length}), void *@var{data}, int *@var{err})
This function calls @var{pfn} for each section in @var{simple_object}.
It calls @var{pfn} with the section name, the offset within the file
of the section contents, and the length of the section contents. The
offset within the file is relative to the offset passed to
@code{simple_object_open_read}. The @var{data} argument to this
function is passed along to @var{pfn}.
If @var{pfn} returns @code{0}, the loop over the sections stops and
@code{simple_object_find_sections} returns. If @var{pfn} returns some
other value, the loop continues.
On success @code{simple_object_find_sections} returns. On error it
returns an error string, and sets @code{*@var{err}} to an errno value
or @code{0} if there is no relevant errno.
@end deftypefn
@c simple-object.txh:2
@deftypefn Extension {simple_object_read *} simple_object_open_read (int @var{descriptor}, off_t @var{offset}, const char *{segment_name}, const char **@var{errmsg}, int *@var{err})
Opens an object file for reading. Creates and returns an
@code{simple_object_read} pointer which may be passed to other
functions to extract data from the object file.
@var{descriptor} holds a file descriptor which permits reading.
@var{offset} is the offset into the file; this will be @code{0} in the
normal case, but may be a different value when reading an object file
in an archive file.
@var{segment_name} is only used with the Mach-O file format used on
Darwin aka Mac OS X. It is required on that platform, and means to
only look at sections within the segment with that name. The
parameter is ignored on other systems.
If an error occurs, this functions returns @code{NULL} and sets
@code{*@var{errmsg}} to an error string and sets @code{*@var{err}} to
an errno value or @code{0} if there is no relevant errno.
@end deftypefn
@c simple-object.txh:96
@deftypefn Extension {void} simple_object_release_attributes (simple_object_attributes *@var{attrs})
Release all resources associated with @var{attrs}.
@end deftypefn
@c simple-object.txh:66
@deftypefn Extension {void} simple_object_release_read (simple_object_read *@var{simple_object})
Release all resources associated with @var{simple_object}. This does
not close the file descriptor.
@end deftypefn
@c simple-object.txh:164
@deftypefn Extension {void} simple_object_release_write (simple_object_write *@var{simple_object})
Release all resources associated with @var{simple_object}.
@end deftypefn
@c simple-object.txh:102
@deftypefn Extension {simple_object_write *} simple_object_start_write (simple_object_attributes @var{attrs}, const char *@var{segment_name}, const char **@var{errmsg}, int *@var{err})
Start creating a new object file using the object file format
described in @var{attrs}. You must fetch attribute information from
an existing object file before you can create a new one. There is
currently no support for creating an object file de novo.
@var{segment_name} is only used with Mach-O as found on Darwin aka Mac
OS X. The parameter is required on that target. It means that all
sections are created within the named segment. It is ignored for
other object file formats.
On error @code{simple_object_start_write} returns @code{NULL}, sets
@code{*@var{ERRMSG}} to an error message, and sets @code{*@var{err}}
to an errno value or @code{0} if there is no relevant errno.
@end deftypefn
@c simple-object.txh:137
@deftypefn Extension {const char *} simple_object_write_add_data (simple_object_write *@var{simple_object}, simple_object_write_section *@var{section}, const void *@var{buffer}, size_t @var{size}, int @var{copy}, int *@var{err})
Add data @var{buffer}/@var{size} to @var{section} in
@var{simple_object}. If @var{copy} is non-zero, the data will be
copied into memory if necessary. If @var{copy} is zero, @var{buffer}
must persist until @code{simple_object_write_to_file} is called. is
released.
On success this returns @code{NULL}. On error this returns an error
message, and sets @code{*@var{err}} to an errno value or 0 if there is
no relevant erro.
@end deftypefn
@c simple-object.txh:120
@deftypefn Extension {simple_object_write_section *} simple_object_write_create_section (simple_object_write *@var{simple_object}, const char *@var{name}, unsigned int @var{align}, const char **@var{errmsg}, int *@var{err})
Add a section to @var{simple_object}. @var{name} is the name of the
new section. @var{align} is the required alignment expressed as the
number of required low-order 0 bits (e.g., 2 for alignment to a 32-bit
boundary).
The section is created as containing data, readable, not writable, not
executable, not loaded at runtime. The section is not written to the
file until @code{simple_object_write_to_file} is called.
On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an
error message, and sets @code{*@var{err}} to an errno value or
@code{0} if there is no relevant errno.
@end deftypefn
@c simple-object.txh:151
@deftypefn Extension {const char *} simple_object_write_to_file (simple_object_write *@var{simple_object}, int @var{descriptor}, int *@var{err})
Write the complete object file to @var{descriptor}, an open file
descriptor. This writes out all the data accumulated by calls to
@code{simple_object_write_create_section} and
@var{simple_object_write_add_data}.
This returns @code{NULL} on success. On error this returns an error
message and sets @code{*@var{err}} to an errno value or @code{0} if
there is no relevant errno.
@end deftypefn
@c snprintf.c:28
@deftypefn Supplemental int snprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, ...)

View File

@ -0,0 +1,804 @@
/* simple-object-coff.c -- routines to manipulate COFF object files.
Copyright 2010 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. */
#include "config.h"
#include "libiberty.h"
#include "simple-object.h"
#include <errno.h>
#include <stddef.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include "simple-object-common.h"
/* COFF structures and constants. */
/* COFF file header. */
struct external_filehdr
{
unsigned char f_magic[2]; /* magic number */
unsigned char f_nscns[2]; /* number of sections */
unsigned char f_timdat[4]; /* time & date stamp */
unsigned char f_symptr[4]; /* file pointer to symtab */
unsigned char f_nsyms[4]; /* number of symtab entries */
unsigned char f_opthdr[2]; /* sizeof(optional hdr) */
unsigned char f_flags[2]; /* flags */
};
/* Bits for filehdr f_flags field. */
#define F_EXEC (0x0002)
#define IMAGE_FILE_SYSTEM (0x1000)
#define IMAGE_FILE_DLL (0x2000)
/* COFF section header. */
struct external_scnhdr
{
unsigned char s_name[8]; /* section name */
unsigned char s_paddr[4]; /* physical address, aliased s_nlib */
unsigned char s_vaddr[4]; /* virtual address */
unsigned char s_size[4]; /* section size */
unsigned char s_scnptr[4]; /* file ptr to raw data for section */
unsigned char s_relptr[4]; /* file ptr to relocation */
unsigned char s_lnnoptr[4]; /* file ptr to line numbers */
unsigned char s_nreloc[2]; /* number of relocation entries */
unsigned char s_nlnno[2]; /* number of line number entries */
unsigned char s_flags[4]; /* flags */
};
/* The length of the s_name field in struct external_scnhdr. */
#define SCNNMLEN (8)
/* Bits for scnhdr s_flags field. This includes some bits defined
only for PE. This may need to be moved into coff_magic. */
#define STYP_DATA (1 << 6)
#define IMAGE_SCN_MEM_DISCARDABLE (1 << 25)
#define IMAGE_SCN_MEM_SHARED (1 << 28)
#define IMAGE_SCN_MEM_READ (1 << 30)
#define IMAGE_SCN_ALIGN_POWER_BIT_POS 20
#define IMAGE_SCN_ALIGN_POWER_CONST(val) \
(((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS)
/* COFF symbol table entry. */
#define E_SYMNMLEN 8 /* # characters in a symbol name */
struct external_syment
{
union
{
unsigned char e_name[E_SYMNMLEN];
struct
{
unsigned char e_zeroes[4];
unsigned char e_offset[4];
} e;
} e;
unsigned char e_value[4];
unsigned char e_scnum[2];
unsigned char e_type[2];
unsigned char e_sclass[1];
unsigned char e_numaux[1];
};
/* Length allowed for filename in aux sym format 4. */
#define E_FILNMLEN 18
/* Omits x_sym and other unused variants. */
union external_auxent
{
/* Aux sym format 4: file. */
union
{
char x_fname[E_FILNMLEN];
struct
{
unsigned char x_zeroes[4];
unsigned char x_offset[4];
} x_n;
} x_file;
/* Aux sym format 5: section. */
struct
{
unsigned char x_scnlen[4]; /* section length */
unsigned char x_nreloc[2]; /* # relocation entries */
unsigned char x_nlinno[2]; /* # line numbers */
unsigned char x_checksum[4]; /* section COMDAT checksum */
unsigned char x_associated[2]; /* COMDAT assoc section index */
unsigned char x_comdat[1]; /* COMDAT selection number */
} x_scn;
};
/* Symbol-related constants. */
#define IMAGE_SYM_DEBUG (-2)
#define IMAGE_SYM_TYPE_NULL (0)
#define IMAGE_SYM_DTYPE_NULL (0)
#define IMAGE_SYM_CLASS_STATIC (3)
#define IMAGE_SYM_CLASS_FILE (103)
#define IMAGE_SYM_TYPE \
((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
/* Private data for an simple_object_read. */
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. */
static const struct coff_magic_struct coff_magic[] =
{
/* i386. */
{ 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
/* x86_64. */
{ 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }
};
/* See if we have a COFF file. */
static void *
simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
int descriptor, off_t offset,
const char *segment_name ATTRIBUTE_UNUSED,
const char **errmsg, int *err)
{
size_t c;
unsigned short magic_big;
unsigned short magic_little;
unsigned short magic;
size_t i;
int is_big_endian;
unsigned short (*fetch_16) (const unsigned char *);
unsigned int (*fetch_32) (const unsigned char *);
unsigned char hdrbuf[sizeof (struct external_filehdr)];
unsigned short flags;
struct simple_object_coff_read *ocr;
c = sizeof (coff_magic) / sizeof (coff_magic[0]);
magic_big = simple_object_fetch_big_16 (header);
magic_little = simple_object_fetch_little_16 (header);
for (i = 0; i < c; ++i)
{
if (coff_magic[i].is_big_endian
? coff_magic[i].magic == magic_big
: coff_magic[i].magic == magic_little)
break;
}
if (i >= c)
{
*errmsg = NULL;
*err = 0;
return NULL;
}
is_big_endian = coff_magic[i].is_big_endian;
magic = is_big_endian ? magic_big : magic_little;
fetch_16 = (is_big_endian
? simple_object_fetch_big_16
: simple_object_fetch_little_16);
fetch_32 = (is_big_endian
? simple_object_fetch_big_32
: simple_object_fetch_little_32);
if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
errmsg, err))
return NULL;
flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags));
if ((flags & coff_magic[i].non_object_flags) != 0)
{
*errmsg = "not relocatable object file";
*err = 0;
return NULL;
}
ocr = XNEW (struct simple_object_coff_read);
ocr->magic = magic;
ocr->is_big_endian = is_big_endian;
ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
ocr->symptr = fetch_32 (hdrbuf
+ offsetof (struct external_filehdr, f_symptr));
ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms));
ocr->flags = flags;
ocr->scnhdr_offset = (sizeof (struct external_filehdr)
+ fetch_16 (hdrbuf + offsetof (struct external_filehdr,
f_opthdr)));
return (void *) ocr;
}
/* Read the string table in a COFF file. */
static char *
simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
const char **errmsg, int *err)
{
struct simple_object_coff_read *ocr =
(struct simple_object_coff_read *) sobj->data;
off_t strtab_offset;
unsigned char strsizebuf[4];
size_t strsize;
char *strtab;
strtab_offset = ocr->symptr + ocr->nsyms * sizeof (struct external_syment);
if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
strsizebuf, 4, errmsg, err))
return NULL;
strsize = (ocr->is_big_endian
? simple_object_fetch_big_32 (strsizebuf)
: simple_object_fetch_little_32 (strsizebuf));
strtab = XNEWVEC (char, strsize);
if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
(unsigned char *) strtab, strsize, errmsg,
err))
{
XDELETEVEC (strtab);
return NULL;
}
*strtab_size = strsize;
return strtab;
}
/* Find all sections in a COFF file. */
static const char *
simple_object_coff_find_sections (simple_object_read *sobj,
int (*pfn) (void *, const char *,
off_t offset, off_t length),
void *data,
int *err)
{
struct simple_object_coff_read *ocr =
(struct simple_object_coff_read *) sobj->data;
size_t scnhdr_size;
unsigned char *scnbuf;
const char *errmsg;
unsigned int (*fetch_32) (const unsigned char *);
unsigned int nscns;
char *strtab;
size_t strtab_size;
unsigned int i;
scnhdr_size = sizeof (struct external_scnhdr);
scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
if (!simple_object_internal_read (sobj->descriptor,
sobj->offset + ocr->scnhdr_offset,
scnbuf, scnhdr_size * ocr->nscns, &errmsg,
err))
{
XDELETEVEC (scnbuf);
return errmsg;
}
fetch_32 = (ocr->is_big_endian
? simple_object_fetch_big_32
: simple_object_fetch_little_32);
nscns = ocr->nscns;
strtab = NULL;
strtab_size = 0;
for (i = 0; i < nscns; ++i)
{
unsigned char *scnhdr;
unsigned char *scnname;
char namebuf[SCNNMLEN + 1];
char *name;
off_t scnptr;
unsigned int size;
scnhdr = scnbuf + i * scnhdr_size;
scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
memcpy (namebuf, scnname, SCNNMLEN);
namebuf[SCNNMLEN] = '\0';
name = &namebuf[0];
if (namebuf[0] == '/')
{
size_t strindex;
char *end;
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";
}
name = strtab + strindex;
}
}
scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr));
size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size));
if (!(*pfn) (data, name, scnptr, size))
break;
}
if (strtab != NULL)
XDELETEVEC (strtab);
XDELETEVEC (scnbuf);
return NULL;
}
/* Fetch the attributes for an simple_object_read. */
static void *
simple_object_coff_fetch_attributes (simple_object_read *sobj,
const char **errmsg ATTRIBUTE_UNUSED,
int *err ATTRIBUTE_UNUSED)
{
struct simple_object_coff_read *ocr =
(struct simple_object_coff_read *) sobj->data;
struct simple_object_coff_attributes *ret;
ret = XNEW (struct simple_object_coff_attributes);
ret->magic = ocr->magic;
ret->is_big_endian = ocr->is_big_endian;
ret->flags = ocr->flags;
return ret;
}
/* Release the private data for an simple_object_read. */
static void
simple_object_coff_release_read (void *data)
{
XDELETE (data);
}
/* Compare two attributes structures. */
static const char *
simple_object_coff_attributes_compare (void *data1, void *data2, int *err)
{
struct simple_object_coff_attributes *attrs1 =
(struct simple_object_coff_attributes *) data1;
struct simple_object_coff_attributes *attrs2 =
(struct simple_object_coff_attributes *) data2;
if (attrs1->magic != attrs2->magic
|| attrs1->is_big_endian != attrs2->is_big_endian)
{
*err = 0;
return "COFF object format mismatch";
}
return NULL;
}
/* Release the private data for an attributes structure. */
static void
simple_object_coff_release_attributes (void *data)
{
XDELETE (data);
}
/* Prepare to write out a file. */
static void *
simple_object_coff_start_write (void *attributes_data,
const char **errmsg ATTRIBUTE_UNUSED,
int *err ATTRIBUTE_UNUSED)
{
struct simple_object_coff_attributes *attrs =
(struct simple_object_coff_attributes *) attributes_data;
struct simple_object_coff_attributes *ret;
/* 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;
}
/* Write out a COFF filehdr. */
static int
simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor,
unsigned int nscns, size_t symtab_offset,
unsigned int nsyms, const char **errmsg,
int *err)
{
struct simple_object_coff_attributes *attrs =
(struct simple_object_coff_attributes *) sobj->data;
unsigned char hdrbuf[sizeof (struct external_filehdr)];
unsigned char *hdr;
void (*set_16) (unsigned char *, unsigned short);
void (*set_32) (unsigned char *, unsigned int);
hdr = &hdrbuf[0];
set_16 = (attrs->is_big_endian
? simple_object_set_big_16
: simple_object_set_little_16);
set_32 = (attrs->is_big_endian
? simple_object_set_big_32
: simple_object_set_little_32);
memset (hdr, 0, sizeof (struct external_filehdr));
set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
/* f_timdat left as zero. */
set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset);
set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms);
/* f_opthdr left as zero. */
set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);
return simple_object_internal_write (descriptor, 0, hdrbuf,
sizeof (struct external_filehdr),
errmsg, err);
}
/* Write out a COFF section header. */
static int
simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor,
const char *name, size_t *name_offset,
off_t scnhdr_offset, size_t scnsize,
off_t offset, unsigned int align,
const char **errmsg, int *err)
{
struct simple_object_coff_attributes *attrs =
(struct simple_object_coff_attributes *) sobj->data;
void (*set_32) (unsigned char *, unsigned int);
unsigned char hdrbuf[sizeof (struct external_scnhdr)];
unsigned char *hdr;
size_t namelen;
unsigned int flags;
set_32 = (attrs->is_big_endian
? simple_object_set_big_32
: simple_object_set_little_32);
memset (hdrbuf, 0, sizeof hdrbuf);
hdr = &hdrbuf[0];
namelen = strlen (name);
if (namelen <= SCNNMLEN)
strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name,
SCNNMLEN);
else
{
snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
SCNNMLEN, "/%lu", (unsigned long) *name_offset);
*name_offset += namelen + 1;
}
/* s_paddr left as zero. */
/* s_vaddr left as zero. */
set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
/* s_relptr left as zero. */
/* s_lnnoptr left as zero. */
/* s_nreloc left as zero. */
/* s_nlnno left as zero. */
flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED
| IMAGE_SCN_MEM_READ);
/* PE can represent alignment up to 13. */
if (align > 13)
align = 13;
flags |= IMAGE_SCN_ALIGN_POWER_CONST(align);
set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags);
return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
sizeof (struct external_scnhdr),
errmsg, err);
}
/* Write out a complete COFF file. */
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);
set_16 = (attrs->is_big_endian
? simple_object_set_big_16
: simple_object_set_little_16);
set_32 = (attrs->is_big_endian
? simple_object_set_big_32
: simple_object_set_little_32);
nscns = 0;
for (section = sobj->sections; section != NULL; section = section->next)
++nscns;
scnhdr_offset = sizeof (struct external_filehdr);
offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
name_offset = 4;
for (section = sobj->sections; section != NULL; section = section->next)
{
size_t mask;
size_t new_offset;
size_t scnsize;
struct simple_object_write_section_buffer *buffer;
mask = (1U << section->align) - 1;
new_offset = offset & mask;
new_offset &= ~ mask;
while (new_offset > offset)
{
unsigned char zeroes[16];
size_t write;
memset (zeroes, 0, sizeof zeroes);
write = new_offset - offset;
if (write > sizeof zeroes)
write = sizeof zeroes;
if (!simple_object_internal_write (descriptor, offset, zeroes, write,
&errmsg, err))
return errmsg;
}
scnsize = 0;
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
{
if (!simple_object_internal_write (descriptor, offset + scnsize,
((const unsigned char *)
buffer->buffer),
buffer->size, &errmsg, err))
return errmsg;
scnsize += buffer->size;
}
if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name,
&name_offset, scnhdr_offset,
scnsize, offset, section->align,
&errmsg, err))
return errmsg;
scnhdr_offset += sizeof (struct external_scnhdr);
offset += scnsize;
}
/* 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;
name_offset = 4;
secsym_offset = symtab_offset + sizeof (syms);
memset (&syms[0], 0, sizeof (syms));
set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC;
syms[0].sym.e_numaux[0] = 1;
secnum = 1;
for (section = sobj->sections; section != NULL; section = section->next)
{
size_t namelen;
size_t scnsize;
struct simple_object_write_section_buffer *buffer;
namelen = strlen (section->name);
set_16 (&syms[0].sym.e_scnum[0], secnum++);
scnsize = 0;
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
scnsize += buffer->size;
set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
if (namelen > SCNNMLEN)
{
set_32 (&syms[0].sym.e.e.e_zeroes[0], 0);
set_32 (&syms[0].sym.e.e.e_offset[0], name_offset);
if (!simple_object_internal_write (descriptor, offset + name_offset,
((const unsigned char *)
section->name),
namelen + 1, &errmsg, err))
return errmsg;
name_offset += namelen + 1;
}
else
{
memcpy (&syms[0].sym.e.e_name[0], section->name,
strlen (section->name));
memset (&syms[0].sym.e.e_name[strlen (section->name)], 0,
E_SYMNMLEN - strlen (section->name));
}
if (!simple_object_internal_write (descriptor, secsym_offset,
(const unsigned char *) &syms[0],
sizeof (syms), &errmsg, err))
return errmsg;
secsym_offset += sizeof (syms);
}
if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns,
symtab_offset, nsyms, &errmsg, err))
return errmsg;
return NULL;
}
/* Release the private data for an simple_object_write structure. */
static void
simple_object_coff_release_write (void *data)
{
XDELETE (data);
}
/* The COFF functions. */
const struct simple_object_functions simple_object_coff_functions =
{
simple_object_coff_match,
simple_object_coff_find_sections,
simple_object_coff_fetch_attributes,
simple_object_coff_release_read,
simple_object_coff_attributes_compare,
simple_object_coff_release_attributes,
simple_object_coff_start_write,
simple_object_coff_write_to_file,
simple_object_coff_release_write
};

View File

@ -0,0 +1,355 @@
/* simple-object-common.h -- common structs for object file manipulation.
Copyright (C) 2010 Free Software Foundation, Inc.
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* Forward reference. */
struct simple_object_functions;
/* An object file opened for reading. */
struct simple_object_read_struct
{
/* The file descriptor. */
int descriptor;
/* The offset within the file. */
off_t offset;
/* The functions which do the actual work. */
const struct simple_object_functions *functions;
/* Private data for the object file format. */
void *data;
};
/* Object file attributes. */
struct simple_object_attributes_struct
{
/* The functions which do the actual work. */
const struct simple_object_functions *functions;
/* Private data for the object file format. */
void *data;
};
/* An object file being created. */
struct simple_object_write_struct
{
/* The functions which do the actual work. */
const struct simple_object_functions *functions;
/* The segment_name argument from the user. */
char *segment_name;
/* The start of the list of sections. */
simple_object_write_section *sections;
/* The last entry in the list of sections. */
simple_object_write_section *last_section;
/* Private data for the object file format. */
void *data;
};
/* A section in an object file being created. */
struct simple_object_write_section_struct
{
/* Next in the list of sections attached to an
simple_object_write. */
simple_object_write_section *next;
/* The name of this section. */
char *name;
/* The required alignment. */
unsigned int align;
/* The first data attached to this section. */
struct simple_object_write_section_buffer *buffers;
/* The last data attached to this section. */
struct simple_object_write_section_buffer *last_buffer;
};
/* Data attached to a section. */
struct simple_object_write_section_buffer
{
/* The next data for this section. */
struct simple_object_write_section_buffer *next;
/* The size of the buffer. */
size_t size;
/* The actual bytes. */
const void *buffer;
/* A buffer to free, or NULL. */
void *free_buffer;
};
/* The number of bytes we read from the start of the file to pass to
the match function. */
#define SIMPLE_OBJECT_MATCH_HEADER_LEN (16)
/* Format-specific object file functions. */
struct simple_object_functions
{
/* If this file matches these functions, return a new value for the
private data for an simple_object_read. HEADER is the first 16
bytes of the file. DESCRIPTOR, OFFSET, SEGMENT_NAME, ERRMSG, and
ERR are as for simple_object_open_read. If this file does not
match, this function should return NULL with *ERRMSG set to
NULL. */
void *(*match) (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
int descriptor, off_t offset, const char *segment_name,
const char **errmsg, int *err);
/* Implement simple_object_find_sections. */
const char *(*find_sections) (simple_object_read *,
int (*pfn) (void *, const char *,
off_t offset, off_t length),
void *data,
int *err);
/* Return the private data for the attributes for SOBJ. */
void *(*fetch_attributes) (simple_object_read *sobj, const char **errmsg,
int *err);
/* Release the private data for an simple_object_read. */
void (*release_read) (void *);
/* Compare the private data for the attributes of two files. If
they are the same, in the sense that they could be linked
together, return NULL. Otherwise return an error message. */
const char *(*attributes_compare) (void *, void *, int *err);
/* Release the private data for an simple_object_attributes. */
void (*release_attributes) (void *);
/* Start creating an object file. */
void *(*start_write) (void *attributes_data, const char **errmsg,
int *err);
/* Write the complete object file. */
const char *(*write_to_file) (simple_object_write *sobj, int descriptor,
int *err);
/* Release the private data for an simple_object_write. */
void (*release_write) (void *);
};
/* The known object file formats. */
extern const struct simple_object_functions simple_object_coff_functions;
extern const struct simple_object_functions simple_object_elf_functions;
extern const struct simple_object_functions simple_object_mach_o_functions;
/* Read SIZE bytes from DESCRIPTOR at file offset OFFSET into BUFFER.
Return non-zero on success. On failure return 0 and set *ERRMSG
and *ERR. */
extern int
simple_object_internal_read (int descriptor, off_t offset,
unsigned char *buffer, size_t size,
const char **errmsg, int *err);
/* Write SIZE bytes from BUFFER to DESCRIPTOR at file offset OFFSET.
Return non-zero on success. On failure return 0 and set *ERRMSG
and *ERR. */
extern int
simple_object_internal_write (int descriptor, off_t offset,
const unsigned char *buffer, size_t size,
const char **errmsg, int *err);
/* Define ulong_type as an unsigned 64-bit type if available.
Otherwise just make it unsigned long. */
#ifdef UNSIGNED_64BIT_TYPE
__extension__ typedef UNSIGNED_64BIT_TYPE ulong_type;
#else
typedef unsigned long ulong_type;
#endif
/* Fetch a big-endian 16-bit value. */
static inline unsigned short
simple_object_fetch_big_16 (const unsigned char *buf)
{
return ((unsigned short) buf[0] << 8) | (unsigned short) buf[1];
}
/* Fetch a little-endian 16-bit value. */
static inline unsigned short
simple_object_fetch_little_16 (const unsigned char *buf)
{
return ((unsigned short) buf[1] << 8) | (unsigned short) buf[0];
}
/* Fetch a big-endian 32-bit value. */
static inline unsigned int
simple_object_fetch_big_32 (const unsigned char *buf)
{
return (((unsigned int) buf[0] << 24)
| ((unsigned int) buf[1] << 16)
| ((unsigned int) buf[2] << 8)
| (unsigned int) buf[3]);
}
/* Fetch a little-endian 32-bit value. */
static inline unsigned int
simple_object_fetch_little_32 (const unsigned char *buf)
{
return (((unsigned int) buf[3] << 24)
| ((unsigned int) buf[2] << 16)
| ((unsigned int) buf[1] << 8)
| (unsigned int) buf[0]);
}
/* Fetch a big-endian 32-bit value as a ulong_type. */
static inline ulong_type
simple_object_fetch_big_32_ulong (const unsigned char *buf)
{
return (ulong_type) simple_object_fetch_big_32 (buf);
}
/* Fetch a little-endian 32-bit value as a ulong_type. */
static inline ulong_type
simple_object_fetch_little_32_ulong (const unsigned char *buf)
{
return (ulong_type) simple_object_fetch_little_32 (buf);
}
#ifdef UNSIGNED_64BIT_TYPE
/* Fetch a big-endian 64-bit value. */
static inline ulong_type
simple_object_fetch_big_64 (const unsigned char *buf)
{
return (((ulong_type) buf[0] << 56)
| ((ulong_type) buf[1] << 48)
| ((ulong_type) buf[2] << 40)
| ((ulong_type) buf[3] << 32)
| ((ulong_type) buf[4] << 24)
| ((ulong_type) buf[5] << 16)
| ((ulong_type) buf[6] << 8)
| (ulong_type) buf[7]);
}
/* Fetch a little-endian 64-bit value. */
static inline ulong_type
simple_object_fetch_little_64 (const unsigned char *buf)
{
return (((ulong_type) buf[7] << 56)
| ((ulong_type) buf[6] << 48)
| ((ulong_type) buf[5] << 40)
| ((ulong_type) buf[4] << 32)
| ((ulong_type) buf[3] << 24)
| ((ulong_type) buf[2] << 16)
| ((ulong_type) buf[1] << 8)
| (ulong_type) buf[0]);
}
#endif
/* Store a big-endian 16-bit value. */
static inline void
simple_object_set_big_16 (unsigned char *buf, unsigned short val)
{
buf[0] = (val >> 8) & 0xff;
buf[1] = val & 0xff;
}
/* Store a little-endian 16-bit value. */
static inline void
simple_object_set_little_16 (unsigned char *buf, unsigned short val)
{
buf[1] = (val >> 8) & 0xff;
buf[0] = val & 0xff;
}
/* Store a big-endian 32-bit value. */
static inline void
simple_object_set_big_32 (unsigned char *buf, unsigned int val)
{
buf[0] = (val >> 24) & 0xff;
buf[1] = (val >> 16) & 0xff;
buf[2] = (val >> 8) & 0xff;
buf[3] = val & 0xff;
}
/* Store a little-endian 32-bit value. */
static inline void
simple_object_set_little_32 (unsigned char *buf, unsigned int val)
{
buf[3] = (val >> 24) & 0xff;
buf[2] = (val >> 16) & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[0] = val & 0xff;
}
/* Store a big-endian 32-bit value coming in as a ulong_type. */
static inline void
simple_object_set_big_32_ulong (unsigned char *buf, ulong_type val)
{
simple_object_set_big_32 (buf, val);
}
/* Store a little-endian 32-bit value coming in as a ulong_type. */
static inline void
simple_object_set_little_32_ulong (unsigned char *buf, ulong_type val)
{
simple_object_set_little_32 (buf, val);
}
#ifdef UNSIGNED_64BIT_TYPE
/* Store a big-endian 64-bit value. */
static inline void
simple_object_set_big_64 (unsigned char *buf, ulong_type val)
{
buf[0] = (val >> 56) & 0xff;
buf[1] = (val >> 48) & 0xff;
buf[2] = (val >> 40) & 0xff;
buf[3] = (val >> 32) & 0xff;
buf[4] = (val >> 24) & 0xff;
buf[5] = (val >> 16) & 0xff;
buf[6] = (val >> 8) & 0xff;
buf[7] = val & 0xff;
}
/* Store a little-endian 64-bit value. */
static inline void
simple_object_set_little_64 (unsigned char *buf, ulong_type val)
{
buf[7] = (val >> 56) & 0xff;
buf[6] = (val >> 48) & 0xff;
buf[5] = (val >> 40) & 0xff;
buf[4] = (val >> 32) & 0xff;
buf[3] = (val >> 24) & 0xff;
buf[2] = (val >> 16) & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[0] = val & 0xff;
}
#endif

View File

@ -0,0 +1,916 @@
/* simple-object-elf.c -- routines to manipulate ELF object files.
Copyright 2010 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. */
#include "config.h"
#include "libiberty.h"
#include "simple-object.h"
#include <errno.h>
#include <stddef.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include "simple-object-common.h"
/* ELF structures and constants. */
/* 32-bit ELF file header. */
typedef struct {
unsigned char e_ident[16]; /* ELF "magic number" */
unsigned char e_type[2]; /* Identifies object file type */
unsigned char e_machine[2]; /* Specifies required architecture */
unsigned char e_version[4]; /* Identifies object file version */
unsigned char e_entry[4]; /* Entry point virtual address */
unsigned char e_phoff[4]; /* Program header table file offset */
unsigned char e_shoff[4]; /* Section header table file offset */
unsigned char e_flags[4]; /* Processor-specific flags */
unsigned char e_ehsize[2]; /* ELF header size in bytes */
unsigned char e_phentsize[2]; /* Program header table entry size */
unsigned char e_phnum[2]; /* Program header table entry count */
unsigned char e_shentsize[2]; /* Section header table entry size */
unsigned char e_shnum[2]; /* Section header table entry count */
unsigned char e_shstrndx[2]; /* Section header string table index */
} Elf32_External_Ehdr;
/* 64-bit ELF file header. */
typedef struct {
unsigned char e_ident[16]; /* ELF "magic number" */
unsigned char e_type[2]; /* Identifies object file type */
unsigned char e_machine[2]; /* Specifies required architecture */
unsigned char e_version[4]; /* Identifies object file version */
unsigned char e_entry[8]; /* Entry point virtual address */
unsigned char e_phoff[8]; /* Program header table file offset */
unsigned char e_shoff[8]; /* Section header table file offset */
unsigned char e_flags[4]; /* Processor-specific flags */
unsigned char e_ehsize[2]; /* ELF header size in bytes */
unsigned char e_phentsize[2]; /* Program header table entry size */
unsigned char e_phnum[2]; /* Program header table entry count */
unsigned char e_shentsize[2]; /* Section header table entry size */
unsigned char e_shnum[2]; /* Section header table entry count */
unsigned char e_shstrndx[2]; /* Section header string table index */
} Elf64_External_Ehdr;
/* Indexes and values in e_ident field of Ehdr. */
#define EI_MAG0 0 /* File identification byte 0 index */
#define ELFMAG0 0x7F /* Magic number byte 0 */
#define EI_MAG1 1 /* File identification byte 1 index */
#define ELFMAG1 'E' /* Magic number byte 1 */
#define EI_MAG2 2 /* File identification byte 2 index */
#define ELFMAG2 'L' /* Magic number byte 2 */
#define EI_MAG3 3 /* File identification byte 3 index */
#define ELFMAG3 'F' /* Magic number byte 3 */
#define EI_CLASS 4 /* File class */
#define ELFCLASSNONE 0 /* Invalid class */
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
#define EI_DATA 5 /* Data encoding */
#define ELFDATANONE 0 /* Invalid data encoding */
#define ELFDATA2LSB 1 /* 2's complement, little endian */
#define ELFDATA2MSB 2 /* 2's complement, big endian */
#define EI_VERSION 6 /* File version */
#define EV_CURRENT 1 /* Current version */
#define EI_OSABI 7 /* Operating System/ABI indication */
/* Values for e_type field of Ehdr. */
#define ET_REL 1 /* Relocatable file */
/* Special section index values. */
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
/* 32-bit ELF program header. */
typedef struct {
unsigned char p_type[4]; /* Identifies program segment type */
unsigned char p_offset[4]; /* Segment file offset */
unsigned char p_vaddr[4]; /* Segment virtual address */
unsigned char p_paddr[4]; /* Segment physical address */
unsigned char p_filesz[4]; /* Segment size in file */
unsigned char p_memsz[4]; /* Segment size in memory */
unsigned char p_flags[4]; /* Segment flags */
unsigned char p_align[4]; /* Segment alignment, file & memory */
} Elf32_External_Phdr;
/* 64-bit ELF program header. */
typedef struct {
unsigned char p_type[4]; /* Identifies program segment type */
unsigned char p_flags[4]; /* Segment flags */
unsigned char p_offset[8]; /* Segment file offset */
unsigned char p_vaddr[8]; /* Segment virtual address */
unsigned char p_paddr[8]; /* Segment physical address */
unsigned char p_filesz[8]; /* Segment size in file */
unsigned char p_memsz[8]; /* Segment size in memory */
unsigned char p_align[8]; /* Segment alignment, file & memory */
} Elf64_External_Phdr;
/* 32-bit ELF section header */
typedef struct {
unsigned char sh_name[4]; /* Section name, index in string tbl */
unsigned char sh_type[4]; /* Type of section */
unsigned char sh_flags[4]; /* Miscellaneous section attributes */
unsigned char sh_addr[4]; /* Section virtual addr at execution */
unsigned char sh_offset[4]; /* Section file offset */
unsigned char sh_size[4]; /* Size of section in bytes */
unsigned char sh_link[4]; /* Index of another section */
unsigned char sh_info[4]; /* Additional section information */
unsigned char sh_addralign[4]; /* Section alignment */
unsigned char sh_entsize[4]; /* Entry size if section holds table */
} Elf32_External_Shdr;
/* 64-bit ELF section header. */
typedef struct {
unsigned char sh_name[4]; /* Section name, index in string tbl */
unsigned char sh_type[4]; /* Type of section */
unsigned char sh_flags[8]; /* Miscellaneous section attributes */
unsigned char sh_addr[8]; /* Section virtual addr at execution */
unsigned char sh_offset[8]; /* Section file offset */
unsigned char sh_size[8]; /* Size of section in bytes */
unsigned char sh_link[4]; /* Index of another section */
unsigned char sh_info[4]; /* Additional section information */
unsigned char sh_addralign[8]; /* Section alignment */
unsigned char sh_entsize[8]; /* Entry size if section holds table */
} Elf64_External_Shdr;
/* Values for sh_type field. */
#define SHT_PROGBITS 1 /* Program data */
#define SHT_STRTAB 3 /* A string table */
/* Functions to fetch and store different ELF types, depending on the
endianness and size. */
struct elf_type_functions
{
unsigned short (*fetch_Elf_Half) (const unsigned char *);
unsigned int (*fetch_Elf_Word) (const unsigned char *);
ulong_type (*fetch_Elf_Addr) (const unsigned char *);
void (*set_Elf_Half) (unsigned char *, unsigned short);
void (*set_Elf_Word) (unsigned char *, unsigned int);
void (*set_Elf_Addr) (unsigned char *, ulong_type);
};
static const struct elf_type_functions elf_big_32_functions =
{
simple_object_fetch_big_16,
simple_object_fetch_big_32,
simple_object_fetch_big_32_ulong,
simple_object_set_big_16,
simple_object_set_big_32,
simple_object_set_big_32_ulong
};
static const struct elf_type_functions elf_little_32_functions =
{
simple_object_fetch_little_16,
simple_object_fetch_little_32,
simple_object_fetch_little_32_ulong,
simple_object_set_little_16,
simple_object_set_little_32,
simple_object_set_little_32_ulong
};
#ifdef UNSIGNED_64BIT_TYPE
static const struct elf_type_functions elf_big_64_functions =
{
simple_object_fetch_big_16,
simple_object_fetch_big_32,
simple_object_fetch_big_64,
simple_object_set_big_16,
simple_object_set_big_32,
simple_object_set_big_64
};
static const struct elf_type_functions elf_little_64_functions =
{
simple_object_fetch_little_16,
simple_object_fetch_little_32,
simple_object_fetch_little_64,
simple_object_set_little_16,
simple_object_set_little_32,
simple_object_set_little_64
};
#endif
/* Hideous macro to fetch the value of a field from an external ELF
struct of some sort. TYPEFUNCS is the set of type functions.
BUFFER points to the external data. STRUCTTYPE is the appropriate
struct type. FIELD is a field within the struct. TYPE is the type
of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr. */
#define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
/* Even more hideous macro to fetch the value of FIELD from BUFFER.
SIZE is 32 or 64. STRUCTTYPE is the name of the struct from
elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in
the struct. TYPE is the type of the field in the struct: Elf_Half,
Elf_Word, or Elf_Addr. */
#define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, \
FIELD, TYPE) \
ELF_FETCH_STRUCT_FIELD (TYPEFUNCS, \
Elf ## SIZE ## _External_ ## STRUCTTYPE, \
FIELD, BUFFER, TYPE)
/* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value. */
#define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, \
FIELD, TYPE) \
((CLASS) == ELFCLASS32 \
? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \
TYPE) \
: ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \
TYPE))
/* Hideous macro to set the value of a field in an external ELF
structure to VAL. TYPEFUNCS is the set of type functions. BUFFER
points to the external data. STRUCTTYPE is the appropriate
structure type. FIELD is a field within the struct. TYPE is the
type of the field in the struct: Elf_Half, Elf_Word, or
Elf_Addr. */
#define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
(TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
/* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
SIZE is 32 or 64. STRUCTTYPE is the name of the struct from
elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in
the struct. TYPE is the type of the field in the struct: Elf_Half,
Elf_Word, or Elf_Addr. */
#define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
TYPE, VAL) \
ELF_SET_STRUCT_FIELD (TYPEFUNCS, \
Elf ## SIZE ## _External_ ## STRUCTTYPE, \
FIELD, BUFFER, TYPE, VAL)
/* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value. */
#define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD, \
TYPE, VAL) \
((CLASS) == ELFCLASS32 \
? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \
TYPE, VAL) \
: ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \
TYPE, VAL))
/* Private data for an simple_object_read. */
struct simple_object_elf_read
{
/* Type functions. */
const struct elf_type_functions* type_functions;
/* Elf data. */
unsigned char ei_data;
/* Elf class. */
unsigned char ei_class;
/* ELF OS ABI. */
unsigned char ei_osabi;
/* Elf machine number. */
unsigned short machine;
/* Processor specific flags. */
unsigned int flags;
/* File offset of section headers. */
ulong_type shoff;
/* Number of sections. */
unsigned int shnum;
/* Index of string table section header. */
unsigned int shstrndx;
};
/* Private data for an simple_object_attributes. */
struct simple_object_elf_attributes
{
/* Type functions. */
const struct elf_type_functions* type_functions;
/* Elf data. */
unsigned char ei_data;
/* Elf class. */
unsigned char ei_class;
/* ELF OS ABI. */
unsigned char ei_osabi;
/* Elf machine number. */
unsigned short machine;
/* Processor specific flags. */
unsigned int flags;
};
/* See if we have an ELF file. */
static void *
simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
int descriptor, off_t offset,
const char *segment_name ATTRIBUTE_UNUSED,
const char **errmsg, int *err)
{
unsigned char ei_data;
unsigned char ei_class;
const struct elf_type_functions *type_functions;
unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
struct simple_object_elf_read *eor;
if (header[EI_MAG0] != ELFMAG0
|| header[EI_MAG1] != ELFMAG1
|| header[EI_MAG2] != ELFMAG2
|| header[EI_MAG3] != ELFMAG3
|| header[EI_VERSION] != EV_CURRENT)
{
*errmsg = NULL;
*err = 0;
return NULL;
}
ei_data = header[EI_DATA];
if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
{
*errmsg = "unknown ELF endianness";
*err = 0;
return NULL;
}
ei_class = header[EI_CLASS];
switch (ei_class)
{
case ELFCLASS32:
type_functions = (ei_data == ELFDATA2LSB
? &elf_little_32_functions
: &elf_big_32_functions);
break;
case ELFCLASS64:
#ifndef UNSIGNED_64BIT_TYPE
*errmsg = "64-bit ELF objects not supported";
*err = 0;
return NULL;
#else
type_functions = (ei_data == ELFDATA2LSB
? &elf_little_64_functions
: &elf_big_64_functions);
break;
#endif
default:
*errmsg = "unrecognized ELF size";
*err = 0;
return NULL;
}
if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr,
errmsg, err))
return NULL;
eor = XNEW (struct simple_object_elf_read);
eor->type_functions = type_functions;
eor->ei_data = ei_data;
eor->ei_class = ei_class;
eor->ei_osabi = header[EI_OSABI];
eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
e_machine, Elf_Half);
eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
e_flags, Elf_Word);
eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
e_shoff, Elf_Addr);
eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
e_shnum, Elf_Half);
eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
e_shstrndx, Elf_Half);
if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
&& eor->shoff != 0)
{
unsigned char shdr[sizeof (Elf64_External_Shdr)];
/* Object file has more than 0xffff sections. */
if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr,
(ei_class == ELFCLASS32
? sizeof (Elf32_External_Shdr)
: sizeof (Elf64_External_Shdr)),
errmsg, err))
{
XDELETE (eor);
return NULL;
}
if (eor->shnum == 0)
eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
shdr, sh_size, Elf_Addr);
if (eor->shstrndx == SHN_XINDEX)
{
eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
shdr, sh_link, Elf_Word);
/* Versions of the GNU binutils between 2.12 and 2.18 did
not handle objects with more than SHN_LORESERVE sections
correctly. All large section indexes were offset by
0x100. There is more information at
http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
Fortunately these object files are easy to detect, as the
GNU binutils always put the section header string table
near the end of the list of sections. Thus if the
section header string table index is larger than the
number of sections, then we know we have to subtract
0x100 to get the real section index. */
if (eor->shstrndx >= eor->shnum
&& eor->shstrndx >= SHN_LORESERVE + 0x100)
eor->shstrndx -= 0x100;
}
}
if (eor->shstrndx >= eor->shnum)
{
*errmsg = "invalid ELF shstrndx >= shnum";
*err = 0;
XDELETE (eor);
return NULL;
}
return (void *) eor;
}
/* Find all sections in an ELF file. */
static const char *
simple_object_elf_find_sections (simple_object_read *sobj,
int (*pfn) (void *, const char *,
off_t offset, off_t length),
void *data,
int *err)
{
struct simple_object_elf_read *eor =
(struct simple_object_elf_read *) sobj->data;
const struct elf_type_functions *type_functions = eor->type_functions;
unsigned char ei_class = eor->ei_class;
size_t shdr_size;
unsigned int shnum;
unsigned char *shdrs;
const char *errmsg;
unsigned char *shstrhdr;
size_t name_size;
off_t shstroff;
unsigned char *names;
unsigned int i;
shdr_size = (ei_class == ELFCLASS32
? sizeof (Elf32_External_Shdr)
: sizeof (Elf64_External_Shdr));
/* Read the section headers. We skip section 0, which is not a
useful section. */
shnum = eor->shnum;
shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
if (!simple_object_internal_read (sobj->descriptor,
sobj->offset + eor->shoff + shdr_size,
shdrs,
shdr_size * (shnum - 1),
&errmsg, err))
{
XDELETEVEC (shdrs);
return errmsg;
}
/* Read the section names. */
shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
shstrhdr, sh_size, Elf_Addr);
shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
shstrhdr, sh_offset, Elf_Addr);
names = XNEWVEC (unsigned char, name_size);
if (!simple_object_internal_read (sobj->descriptor,
sobj->offset + shstroff,
names, name_size, &errmsg, err))
{
XDELETEVEC (names);
XDELETEVEC (shdrs);
return errmsg;
}
for (i = 1; i < shnum; ++i)
{
unsigned char *shdr;
unsigned int sh_name;
const char *name;
off_t offset;
off_t length;
shdr = shdrs + (i - 1) * shdr_size;
sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
shdr, sh_name, Elf_Word);
if (sh_name >= name_size)
{
*err = 0;
XDELETEVEC (names);
XDELETEVEC (shdrs);
return "ELF section name out of range";
}
name = (const char *) names + sh_name;
offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
shdr, sh_offset, Elf_Addr);
length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
shdr, sh_size, Elf_Addr);
if (!(*pfn) (data, name, offset, length))
break;
}
XDELETEVEC (names);
XDELETEVEC (shdrs);
return NULL;
}
/* Fetch the attributes for an simple_object_read. */
static void *
simple_object_elf_fetch_attributes (simple_object_read *sobj,
const char **errmsg ATTRIBUTE_UNUSED,
int *err ATTRIBUTE_UNUSED)
{
struct simple_object_elf_read *eor =
(struct simple_object_elf_read *) sobj->data;
struct simple_object_elf_attributes *ret;
ret = XNEW (struct simple_object_elf_attributes);
ret->type_functions = eor->type_functions;
ret->ei_data = eor->ei_data;
ret->ei_class = eor->ei_class;
ret->ei_osabi = eor->ei_osabi;
ret->machine = eor->machine;
ret->flags = eor->flags;
return ret;
}
/* Release the privata data for an simple_object_read. */
static void
simple_object_elf_release_read (void *data)
{
XDELETE (data);
}
/* Compare two attributes structures. */
static const char *
simple_object_elf_attributes_compare (void *data1, void *data2, int *err)
{
struct simple_object_elf_attributes *attrs1 =
(struct simple_object_elf_attributes *) data1;
struct simple_object_elf_attributes *attrs2 =
(struct simple_object_elf_attributes *) data2;
if (attrs1->ei_data != attrs2->ei_data
|| attrs1->ei_class != attrs2->ei_class
|| attrs1->machine != attrs2->machine)
{
*err = 0;
return "ELF object format mismatch";
}
return NULL;
}
/* Release the private data for an attributes structure. */
static void
simple_object_elf_release_attributes (void *data)
{
XDELETE (data);
}
/* Prepare to write out a file. */
static void *
simple_object_elf_start_write (void *attributes_data,
const char **errmsg ATTRIBUTE_UNUSED,
int *err ATTRIBUTE_UNUSED)
{
struct simple_object_elf_attributes *attrs =
(struct simple_object_elf_attributes *) attributes_data;
struct simple_object_elf_attributes *ret;
/* 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_elf_attributes);
*ret = *attrs;
return ret;
}
/* Write out an ELF ehdr. */
static int
simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
const char **errmsg, int *err)
{
struct simple_object_elf_attributes *attrs =
(struct simple_object_elf_attributes *) sobj->data;
const struct elf_type_functions* fns;
unsigned char cl;
size_t ehdr_size;
unsigned char buf[sizeof (Elf64_External_Ehdr)];
simple_object_write_section *section;
unsigned int shnum;
fns = attrs->type_functions;
cl = attrs->ei_class;
shnum = 0;
for (section = sobj->sections; section != NULL; section = section->next)
++shnum;
if (shnum > 0)
{
/* Add a section header for the dummy section and one for
.shstrtab. */
shnum += 2;
}
ehdr_size = (cl == ELFCLASS32
? sizeof (Elf32_External_Ehdr)
: sizeof (Elf64_External_Ehdr));
memset (buf, 0, sizeof (Elf64_External_Ehdr));
buf[EI_MAG0] = ELFMAG0;
buf[EI_MAG1] = ELFMAG1;
buf[EI_MAG2] = ELFMAG2;
buf[EI_MAG3] = ELFMAG3;
buf[EI_CLASS] = cl;
buf[EI_DATA] = attrs->ei_data;
buf[EI_VERSION] = EV_CURRENT;
buf[EI_OSABI] = attrs->ei_osabi;
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
/* e_entry left as zero. */
/* e_phoff left as zero. */
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
(cl == ELFCLASS32
? sizeof (Elf32_External_Phdr)
: sizeof (Elf64_External_Phdr)));
/* e_phnum left as zero. */
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
(cl == ELFCLASS32
? sizeof (Elf32_External_Shdr)
: sizeof (Elf64_External_Shdr)));
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum);
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half,
shnum == 0 ? 0 : shnum - 1);
return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
errmsg, err);
}
/* Write out an ELF shdr. */
static int
simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
off_t offset, unsigned int sh_name,
unsigned int sh_type, unsigned int sh_flags,
unsigned int sh_offset, unsigned int sh_size,
unsigned int sh_addralign, const char **errmsg,
int *err)
{
struct simple_object_elf_attributes *attrs =
(struct simple_object_elf_attributes *) sobj->data;
const struct elf_type_functions* fns;
unsigned char cl;
size_t shdr_size;
unsigned char buf[sizeof (Elf64_External_Shdr)];
fns = attrs->type_functions;
cl = attrs->ei_class;
shdr_size = (cl == ELFCLASS32
? sizeof (Elf32_External_Shdr)
: sizeof (Elf64_External_Shdr));
memset (buf, 0, sizeof (Elf64_External_Shdr));
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
/* sh_link left as zero. */
/* sh_info left as zero. */
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
/* sh_entsize left as zero. */
return simple_object_internal_write (descriptor, offset, buf, shdr_size,
errmsg, err);
}
/* Write out a complete ELF file.
Ehdr
initial dummy Shdr
user-created Shdrs
.shstrtab Shdr
user-created section data
.shstrtab data */
static const char *
simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
int *err)
{
struct simple_object_elf_attributes *attrs =
(struct simple_object_elf_attributes *) sobj->data;
unsigned char cl;
size_t ehdr_size;
size_t shdr_size;
const char *errmsg;
simple_object_write_section *section;
unsigned int shnum;
size_t shdr_offset;
size_t sh_offset;
size_t sh_name;
unsigned char zero;
if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
return errmsg;
cl = attrs->ei_class;
if (cl == ELFCLASS32)
{
ehdr_size = sizeof (Elf32_External_Ehdr);
shdr_size = sizeof (Elf32_External_Shdr);
}
else
{
ehdr_size = sizeof (Elf64_External_Ehdr);
shdr_size = sizeof (Elf64_External_Shdr);
}
shnum = 0;
for (section = sobj->sections; section != NULL; section = section->next)
++shnum;
if (shnum == 0)
return NULL;
/* Add initial dummy Shdr and .shstrtab. */
shnum += 2;
shdr_offset = ehdr_size;
sh_offset = shdr_offset + shnum * shdr_size;
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
0, 0, 0, 0, 0, 0, &errmsg, err))
return errmsg;
shdr_offset += shdr_size;
sh_name = 1;
for (section = sobj->sections; section != NULL; section = section->next)
{
size_t mask;
size_t new_sh_offset;
size_t sh_size;
struct simple_object_write_section_buffer *buffer;
mask = (1U << section->align) - 1;
new_sh_offset = sh_offset + mask;
new_sh_offset &= ~ mask;
while (new_sh_offset > sh_offset)
{
unsigned char zeroes[16];
size_t write;
memset (zeroes, 0, sizeof zeroes);
write = new_sh_offset - sh_offset;
if (write > sizeof zeroes)
write = sizeof zeroes;
if (!simple_object_internal_write (descriptor, sh_offset, zeroes,
write, &errmsg, err))
return errmsg;
sh_offset += write;
}
sh_size = 0;
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
{
if (!simple_object_internal_write (descriptor, sh_offset + sh_size,
((const unsigned char *)
buffer->buffer),
buffer->size, &errmsg, err))
return errmsg;
sh_size += buffer->size;
}
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
sh_name, SHT_PROGBITS, 0, sh_offset,
sh_size, 1U << section->align,
&errmsg, err))
return errmsg;
shdr_offset += shdr_size;
sh_name += strlen (section->name) + 1;
sh_offset += sh_size;
}
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
sh_name, SHT_STRTAB, 0, sh_offset,
sh_name + strlen (".shstrtab") + 1,
1, &errmsg, err))
return errmsg;
/* .shstrtab has a leading zero byte. */
zero = 0;
if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1,
&errmsg, err))
return errmsg;
++sh_offset;
for (section = sobj->sections; section != NULL; section = section->next)
{
size_t len;
len = strlen (section->name) + 1;
if (!simple_object_internal_write (descriptor, sh_offset,
(const unsigned char *) section->name,
len, &errmsg, err))
return errmsg;
sh_offset += len;
}
if (!simple_object_internal_write (descriptor, sh_offset,
(const unsigned char *) ".shstrtab",
strlen (".shstrtab") + 1, &errmsg, err))
return errmsg;
return NULL;
}
/* Release the private data for an simple_object_write structure. */
static void
simple_object_elf_release_write (void *data)
{
XDELETE (data);
}
/* The ELF functions. */
const struct simple_object_functions simple_object_elf_functions =
{
simple_object_elf_match,
simple_object_elf_find_sections,
simple_object_elf_fetch_attributes,
simple_object_elf_release_read,
simple_object_elf_attributes_compare,
simple_object_elf_release_attributes,
simple_object_elf_start_write,
simple_object_elf_write_to_file,
simple_object_elf_release_write
};

File diff suppressed because it is too large Load Diff

423
libiberty/simple-object.c Normal file
View File

@ -0,0 +1,423 @@
/* simple-object.c -- simple routines to read and write object files.
Copyright 2010 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. */
#include "config.h"
#include "libiberty.h"
#include "simple-object.h"
#include <errno.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#include "simple-object-common.h"
/* The known object file formats. */
static const struct simple_object_functions * const format_functions[] =
{
&simple_object_elf_functions,
&simple_object_mach_o_functions,
&simple_object_coff_functions
};
/* Read data from a file using the simple_object error reporting
conventions. */
int
simple_object_internal_read (int descriptor, off_t offset,
unsigned char *buffer, size_t size,
const char **errmsg, int *err)
{
ssize_t got;
if (lseek (descriptor, offset, SEEK_SET) < 0)
{
*errmsg = "lseek";
*err = errno;
return 0;
}
got = read (descriptor, buffer, size);
if (got < 0)
{
*errmsg = "read";
*err = errno;
return 0;
}
if ((size_t) got < size)
{
*errmsg = "file too short";
*err = 0;
return 0;
}
return 1;
}
/* Write data to a file using the simple_object error reporting
conventions. */
int
simple_object_internal_write (int descriptor, off_t offset,
const unsigned char *buffer, size_t size,
const char **errmsg, int *err)
{
ssize_t wrote;
if (lseek (descriptor, offset, SEEK_SET) < 0)
{
*errmsg = "lseek";
*err = errno;
return 0;
}
wrote = write (descriptor, buffer, size);
if (wrote < 0)
{
*errmsg = "write";
*err = errno;
return 0;
}
if ((size_t) wrote < size)
{
*errmsg = "short write";
*err = 0;
return 0;
}
return 1;
}
/* Open for read. */
simple_object_read *
simple_object_start_read (int descriptor, off_t offset,
const char *segment_name, const char **errmsg,
int *err)
{
unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
size_t len, i;
if (!simple_object_internal_read (descriptor, offset, header,
SIMPLE_OBJECT_MATCH_HEADER_LEN,
errmsg, err))
return NULL;
len = sizeof (format_functions) / sizeof (format_functions[0]);
for (i = 0; i < len; ++i)
{
void *data;
data = format_functions[i]->match (header, descriptor, offset,
segment_name, errmsg, err);
if (data != NULL)
{
simple_object_read *ret;
ret = XNEW (simple_object_read);
ret->descriptor = descriptor;
ret->offset = offset;
ret->functions = format_functions[i];
ret->data = data;
return ret;
}
}
*errmsg = "file not recognized";
*err = 0;
return NULL;
}
/* Find all sections. */
const char *
simple_object_find_sections (simple_object_read *sobj,
int (*pfn) (void *, const char *, off_t, off_t),
void *data,
int *err)
{
return sobj->functions->find_sections (sobj, pfn, data, err);
}
/* Internal data passed to find_one_section. */
struct find_one_section_data
{
/* The section we are looking for. */
const char *name;
/* Where to store the section offset. */
off_t *offset;
/* Where to store the section length. */
off_t *length;
/* Set if the name is found. */
int found;
};
/* Internal function passed to find_sections. */
static int
find_one_section (void *data, const char *name, off_t offset, off_t length)
{
struct find_one_section_data *fosd = (struct find_one_section_data *) data;
if (strcmp (name, fosd->name) != 0)
return 1;
*fosd->offset = offset;
*fosd->length = length;
fosd->found = 1;
/* Stop iteration. */
return 0;
}
/* Find a section. */
int
simple_object_find_section (simple_object_read *sobj, const char *name,
off_t *offset, off_t *length,
const char **errmsg, int *err)
{
struct find_one_section_data fosd;
fosd.name = name;
fosd.offset = offset;
fosd.length = length;
fosd.found = 0;
*errmsg = simple_object_find_sections (sobj, find_one_section,
(void *) &fosd, err);
if (*errmsg != NULL)
return 0;
if (!fosd.found)
return 0;
return 1;
}
/* Fetch attributes. */
simple_object_attributes *
simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
int *err)
{
void *data;
simple_object_attributes *ret;
data = sobj->functions->fetch_attributes (sobj, errmsg, err);
if (data == NULL)
return NULL;
ret = XNEW (simple_object_attributes);
ret->functions = sobj->functions;
ret->data = data;
return ret;
}
/* Release an simple_object_read. */
void
simple_object_release_read (simple_object_read *sobj)
{
sobj->functions->release_read (sobj->data);
XDELETE (sobj);
}
/* Compare attributes. */
const char *
simple_object_attributes_compare (simple_object_attributes *attrs1,
simple_object_attributes *attrs2,
int *err)
{
if (attrs1->functions != attrs2->functions)
{
*err = 0;
return "different object file format";
}
return attrs1->functions->attributes_compare (attrs1->data, attrs2->data,
err);
}
/* Release an attributes structure. */
void
simple_object_release_attributes (simple_object_attributes *attrs)
{
attrs->functions->release_attributes (attrs->data);
XDELETE (attrs);
}
/* Start creating an object file. */
simple_object_write *
simple_object_start_write (simple_object_attributes *attrs,
const char *segment_name, const char **errmsg,
int *err)
{
void *data;
simple_object_write *ret;
data = attrs->functions->start_write (attrs->data, errmsg, err);
if (data == NULL)
return NULL;
ret = XNEW (simple_object_write);
ret->functions = attrs->functions;
ret->segment_name = xstrdup (segment_name);
ret->sections = NULL;
ret->last_section = NULL;
ret->data = data;
return ret;
}
/* Start creating a section. */
simple_object_write_section *
simple_object_write_create_section (simple_object_write *sobj, const char *name,
unsigned int align,
const char **errmsg ATTRIBUTE_UNUSED,
int *err ATTRIBUTE_UNUSED)
{
simple_object_write_section *ret;
ret = XNEW (simple_object_write_section);
ret->next = NULL;
ret->name = xstrdup (name);
ret->align = align;
ret->buffers = NULL;
ret->last_buffer = NULL;
if (sobj->last_section == NULL)
{
sobj->sections = ret;
sobj->last_section = ret;
}
else
{
sobj->last_section->next = ret;
sobj->last_section = ret;
}
return ret;
}
/* Add data to a section. */
const char *
simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
simple_object_write_section *section,
const void *buffer,
size_t size, int copy,
int *err ATTRIBUTE_UNUSED)
{
struct simple_object_write_section_buffer *wsb;
wsb = XNEW (struct simple_object_write_section_buffer);
wsb->next = NULL;
wsb->size = size;
if (!copy)
{
wsb->buffer = buffer;
wsb->free_buffer = NULL;
}
else
{
wsb->free_buffer = (void *) XNEWVEC (char, size);
memcpy (wsb->free_buffer, buffer, size);
wsb->buffer = wsb->free_buffer;
}
if (section->last_buffer == NULL)
{
section->buffers = wsb;
section->last_buffer = wsb;
}
else
{
section->last_buffer->next = wsb;
section->last_buffer = wsb;
}
return NULL;
}
/* Write the complete object file. */
const char *
simple_object_write_to_file (simple_object_write *sobj, int descriptor,
int *err)
{
return sobj->functions->write_to_file (sobj, descriptor, err);
}
/* Release an simple_object_write. */
void
simple_object_release_write (simple_object_write *sobj)
{
simple_object_write_section *section;
free (sobj->segment_name);
section = sobj->sections;
while (section != NULL)
{
struct simple_object_write_section_buffer *buffer;
simple_object_write_section *next_section;
buffer = section->buffers;
while (buffer != NULL)
{
struct simple_object_write_section_buffer *next_buffer;
if (buffer->free_buffer != NULL)
XDELETEVEC (buffer->free_buffer);
next_buffer = buffer->next;
XDELETE (buffer);
buffer = next_buffer;
}
next_section = section->next;
free (section->name);
XDELETE (section);
section = next_section;
}
sobj->functions->release_write (sobj->data);
XDELETE (sobj);
}

168
libiberty/simple-object.txh Normal file
View File

@ -0,0 +1,168 @@
@c -*- mode: texinfo -*-
@deftypefn Extension {simple_object_read *} simple_object_open_read (int @var{descriptor}, off_t @var{offset}, const char *{segment_name}, const char **@var{errmsg}, int *@var{err})
Opens an object file for reading. Creates and returns an
@code{simple_object_read} pointer which may be passed to other
functions to extract data from the object file.
@var{descriptor} holds a file descriptor which permits reading.
@var{offset} is the offset into the file; this will be @code{0} in the
normal case, but may be a different value when reading an object file
in an archive file.
@var{segment_name} is only used with the Mach-O file format used on
Darwin aka Mac OS X. It is required on that platform, and means to
only look at sections within the segment with that name. The
parameter is ignored on other systems.
If an error occurs, this functions returns @code{NULL} and sets
@code{*@var{errmsg}} to an error string and sets @code{*@var{err}} to
an errno value or @code{0} if there is no relevant errno.
@end deftypefn
@deftypefn Extension {const char *} simple_object_find_sections (simple_object_read *@var{simple_object}, int (*@var{pfn}) (void *@var{data}, const char *@var{name}, off_t @var{offset}, off_t @var{length}), void *@var{data}, int *@var{err})
This function calls @var{pfn} for each section in @var{simple_object}.
It calls @var{pfn} with the section name, the offset within the file
of the section contents, and the length of the section contents. The
offset within the file is relative to the offset passed to
@code{simple_object_open_read}. The @var{data} argument to this
function is passed along to @var{pfn}.
If @var{pfn} returns @code{0}, the loop over the sections stops and
@code{simple_object_find_sections} returns. If @var{pfn} returns some
other value, the loop continues.
On success @code{simple_object_find_sections} returns. On error it
returns an error string, and sets @code{*@var{err}} to an errno value
or @code{0} if there is no relevant errno.
@end deftypefn
@deftypefn Extension {int} simple_object_find_section (simple_object_read *@var{simple_object} off_t *@var{offset}, off_t *@var{length}, const char **@var{errmsg}, int *@var{err})
Look for the section @var{name} in @var{simple_object}. This returns
information for the first section with that name.
If found, return 1 and set @code{*@var{offset}} to the offset in the
file of the section contents and set @code{*@var{length}} to the
length of the section contents. The value in @code{*@var{offset}}
will be relative to the offset passed to
@code{simple_object_open_read}.
If the section is not found, and no error occurs,
@code{simple_object_find_section} returns @code{0} and set
@code{*@var{errmsg}} to @code{NULL}.
If an error occurs, @code{simple_object_find_section} returns
@code{0}, sets @code{*@var{errmsg}} to an error message, and sets
@code{*@var{err}} to an errno value or @code{0} if there is no
relevant errno.
@end deftypefn
@deftypefn Extension {void} simple_object_release_read (simple_object_read *@var{simple_object})
Release all resources associated with @var{simple_object}. This does
not close the file descriptor.
@end deftypefn
@deftypefn Extension {simple_object_attributes *} simple_object_fetch_attributes (simple_object_read *@var{simple_object}, const char **@var{errmsg}, int *@var{err})
Fetch the attributes of @var{simple_object}. The attributes are
internal information such as the format of the object file, or the
architecture it was compiled for. This information will persist until
@code{simple_object_attributes_release} is called, even if
@var{simple_object} itself is released.
On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an
error message, and sets @code{*@var{err}} to an errno value or
@code{0} if there is no relevant errno.
@end deftypefn
@deftypefn Extension {const char *} simple_object_attributes_compare (simple_object_attributes *@var{attrs1}, simple_object_attributes *@var{attrs2}, int *@var{err})
Compare @var{attrs1} and @var{attrs2}. If they could be linked
together without error, return @code{NULL}. Otherwise, return an
error message and set @code{*@var{err}} to an errno value or @code{0}
if there is no relevant errno.
@end deftypefn
@deftypefn Extension {void} simple_object_release_attributes (simple_object_attributes *@var{attrs})
Release all resources associated with @var{attrs}.
@end deftypefn
@deftypefn Extension {simple_object_write *} simple_object_start_write (simple_object_attributes @var{attrs}, const char *@var{segment_name}, const char **@var{errmsg}, int *@var{err})
Start creating a new object file using the object file format
described in @var{attrs}. You must fetch attribute information from
an existing object file before you can create a new one. There is
currently no support for creating an object file de novo.
@var{segment_name} is only used with Mach-O as found on Darwin aka Mac
OS X. The parameter is required on that target. It means that all
sections are created within the named segment. It is ignored for
other object file formats.
On error @code{simple_object_start_write} returns @code{NULL}, sets
@code{*@var{ERRMSG}} to an error message, and sets @code{*@var{err}}
to an errno value or @code{0} if there is no relevant errno.
@end deftypefn
@deftypefn Extension {simple_object_write_section *} simple_object_write_create_section (simple_object_write *@var{simple_object}, const char *@var{name}, unsigned int @var{align}, const char **@var{errmsg}, int *@var{err})
Add a section to @var{simple_object}. @var{name} is the name of the
new section. @var{align} is the required alignment expressed as the
number of required low-order 0 bits (e.g., 2 for alignment to a 32-bit
boundary).
The section is created as containing data, readable, not writable, not
executable, not loaded at runtime. The section is not written to the
file until @code{simple_object_write_to_file} is called.
On error this returns @code{NULL}, sets @code{*@var{errmsg}} to an
error message, and sets @code{*@var{err}} to an errno value or
@code{0} if there is no relevant errno.
@end deftypefn
@deftypefn Extension {const char *} simple_object_write_add_data (simple_object_write *@var{simple_object}, simple_object_write_section *@var{section}, const void *@var{buffer}, size_t @var{size}, int @var{copy}, int *@var{err})
Add data @var{buffer}/@var{size} to @var{section} in
@var{simple_object}. If @var{copy} is non-zero, the data will be
copied into memory if necessary. If @var{copy} is zero, @var{buffer}
must persist until @code{simple_object_write_to_file} is called. is
released.
On success this returns @code{NULL}. On error this returns an error
message, and sets @code{*@var{err}} to an errno value or 0 if there is
no relevant erro.
@end deftypefn
@deftypefn Extension {const char *} simple_object_write_to_file (simple_object_write *@var{simple_object}, int @var{descriptor}, int *@var{err})
Write the complete object file to @var{descriptor}, an open file
descriptor. This writes out all the data accumulated by calls to
@code{simple_object_write_create_section} and
@var{simple_object_write_add_data}.
This returns @code{NULL} on success. On error this returns an error
message and sets @code{*@var{err}} to an errno value or @code{0} if
there is no relevant errno.
@end deftypefn
@deftypefn Extension {void} simple_object_release_write (simple_object_write *@var{simple_object})
Release all resources associated with @var{simple_object}.
@end deftypefn