binutils: build AS.

git-svn-id: svn://kolibrios.org@5222 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2014-12-06 08:41:27 +00:00
parent ecd34cd9d9
commit 5490489cbb
70 changed files with 55872 additions and 0 deletions

View File

@ -0,0 +1,45 @@
LIB_DIR:= $(SDK_DIR)/lib
CFLAGS_OPT = -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -U_MSC_VER -O2
CFLAGS_OPT+= -fomit-frame-pointer -fno-ident -mno-ms-bitfields
CFLAGS_OPT+= -W -Wall -Wmissing-prototypes -Wno-format
CFLAGS = -c $(CFLAGS_OPT)
INCLUDES= -I. -I../bfd -I./config -I../include -I../
INCLUDES+= -I$(SDK_DIR)/sources/newlib/libc/include -I$(SDK_DIR)/sources/zlib
DEFINES= -DHAVE_CONFIG_H -DLOCALEDIR='"/home/autobuild/tools/win32/share/locale"'
LIBS= -lopcodes -lbfd -liberty -lz -lgcc -lc.dll -lapp
LIBPATH:= -L$(LIB_DIR) -L/home/autobuild/tools/win32/mingw32/lib
LDFLAGS = -static -nostdlib --stack 12582912 -T$(SDK_DIR)/sources/newlib/app.lds --image-base 0
SRCS = \
app.c as.c atof-generic.c compress-debug.c \
cond.c depend.c dwarf2dbg.c dw2gencfi.c ecoff.c \
ehopt.c expr.c flonum-copy.c flonum-konst.c \
flonum-mult.c frags.c hash.c input-file.c \
input-scrub.c listing.c literal.c macro.c \
messages.c output-file.c read.c remap.c sb.c \
stabs.c subsegs.c symbols.c write.c \
config/atof-ieee.c config/obj-coff.c \
config/tc-i386.c
OBJS = $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS)))
# targets
all: as
as: $(OBJS) Makefile
$(LD) $(LDFLAGS) $(LIBPATH) -o $@ $(OBJS) $(LIBS)
kos32-objcopy $@ -O binary
%.o : %.c Makefile
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $<

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,634 @@
/* as.h - global header file
Copyright 1987-2013 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef GAS
#define GAS 1
/* I think this stuff is largely out of date. xoxorich.
CAPITALISED names are #defined.
"lowercaseH" is #defined if "lowercase.h" has been #include-d.
"lowercaseT" is a typedef of "lowercase" objects.
"lowercaseP" is type "pointer to object of type 'lowercase'".
"lowercaseS" is typedef struct ... lowercaseS.
#define DEBUG to enable all the "know" assertion tests.
#define SUSPECT when debugging hash code.
#define COMMON as "extern" for all modules except one, where you #define
COMMON as "".
If TEST is #defined, then we are testing a module: #define COMMON as "". */
#include "alloca-conf.h"
/* Now, tend to the rest of the configuration. */
/* System include files first... */
#include <stdio.h>
#ifdef STRING_WITH_STRINGS
#include <string.h>
#include <strings.h>
#else
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_TYPES_H
/* for size_t, pid_t */
#include <sys/types.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <stdarg.h>
#include "getopt.h"
/* The first getopt value for machine-independent long options.
150 isn't special; it's just an arbitrary non-ASCII char value. */
#define OPTION_STD_BASE 150
/* The first getopt value for machine-dependent long options.
190 gives the standard options room to grow. */
#define OPTION_MD_BASE 190
#ifdef DEBUG
#undef NDEBUG
#endif
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6)
#define __PRETTY_FUNCTION__ ((char *) NULL)
#endif
#define gas_assert(P) \
((void) ((P) ? 0 : (as_assert (__FILE__, __LINE__, __PRETTY_FUNCTION__), 0)))
#undef abort
#define abort() as_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__)
/* Now GNU header files... */
#include "ansidecl.h"
#include "bfd.h"
#include "libiberty.h"
/* Define the standard progress macros. */
#include "progress.h"
/* This doesn't get taken care of anywhere. */
#ifndef __MWERKS__ /* Metrowerks C chokes on the "defined (inline)" */
#if !defined (__GNUC__) && !defined (inline)
#define inline
#endif
#endif /* !__MWERKS__ */
/* Other stuff from config.h. */
#ifdef NEED_DECLARATION_ENVIRON
extern char **environ;
#endif
#ifdef NEED_DECLARATION_ERRNO
extern int errno;
#endif
#ifdef NEED_DECLARATION_FFS
extern int ffs (int);
#endif
#ifdef NEED_DECLARATION_FREE
extern void free ();
#endif
#ifdef NEED_DECLARATION_MALLOC
extern void *malloc ();
extern void *realloc ();
#endif
#ifdef NEED_DECLARATION_STRSTR
extern char *strstr ();
#endif
#if !HAVE_DECL_MEMPCPY
void *mempcpy(void *, const void *, size_t);
#endif
#if !HAVE_DECL_VSNPRINTF
extern int vsnprintf(char *, size_t, const char *, va_list);
#endif
/* This is needed for VMS. */
#if ! defined (HAVE_UNLINK) && defined (HAVE_REMOVE)
#define unlink remove
#endif
/* Hack to make "gcc -Wall" not complain about obstack macros. */
#if !defined (memcpy) && !defined (bcopy)
#define bcopy(src,dest,size) memcpy (dest, src, size)
#endif
/* Make Saber happier on obstack.h. */
#ifdef SABER
#undef __PTR_TO_INT
#define __PTR_TO_INT(P) ((int) (P))
#undef __INT_TO_PTR
#define __INT_TO_PTR(P) ((char *) (P))
#endif
#ifndef __LINE__
#define __LINE__ "unknown"
#endif /* __LINE__ */
#ifndef __FILE__
#define __FILE__ "unknown"
#endif /* __FILE__ */
#ifndef FOPEN_WB
#ifdef USE_BINARY_FOPEN
#include "fopen-bin.h"
#else
#include "fopen-same.h"
#endif
#endif
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free xfree
#define xfree free
#include "asintl.h"
#define BAD_CASE(val) \
{ \
as_fatal (_("Case value %ld unexpected at line %d of file \"%s\"\n"), \
(long) val, __LINE__, __FILE__); \
}
#include "flonum.h"
/* These are assembler-wide concepts */
extern bfd *stdoutput;
typedef bfd_vma addressT;
typedef bfd_signed_vma offsetT;
/* Type of symbol value, etc. For use in prototypes. */
typedef addressT valueT;
#ifndef COMMON
#ifdef TEST
#define COMMON /* Declare our COMMONs storage here. */
#else
#define COMMON extern /* Our commons live elsewhere. */
#endif
#endif
/* COMMON now defined */
#ifndef ENABLE_CHECKING
#define ENABLE_CHECKING 0
#endif
#if ENABLE_CHECKING || defined (DEBUG)
#ifndef know
#define know(p) gas_assert(p) /* Verify our assumptions! */
#endif /* not yet defined */
#else
#define know(p) do {} while (0) /* know() checks are no-op.ed */
#endif
/* input_scrub.c */
/* Supplies sanitised buffers to read.c.
Also understands printing line-number part of error messages. */
/* subsegs.c Sub-segments. Also, segment(=expression type)s.*/
typedef asection *segT;
#define SEG_NORMAL(SEG) ( (SEG) != absolute_section \
&& (SEG) != undefined_section \
&& (SEG) != reg_section \
&& (SEG) != expr_section)
typedef int subsegT;
/* What subseg we are accessing now? */
COMMON subsegT now_subseg;
/* Segment our instructions emit to. */
COMMON segT now_seg;
#define segment_name(SEG) bfd_get_section_name (stdoutput, SEG)
extern segT reg_section, expr_section;
/* Shouldn't these be eliminated someday? */
extern segT text_section, data_section, bss_section;
#define absolute_section bfd_abs_section_ptr
#define undefined_section bfd_und_section_ptr
enum _relax_state
{
/* Dummy frag used by listing code. */
rs_dummy = 0,
/* Variable chars to be repeated fr_offset times.
Fr_symbol unused. Used with fr_offset == 0 for a
constant length frag. */
rs_fill,
/* Align. The fr_offset field holds the power of 2 to which to
align. The fr_var field holds the number of characters in the
fill pattern. The fr_subtype field holds the maximum number of
bytes to skip when aligning, or 0 if there is no maximum. */
rs_align,
/* Align code. The fr_offset field holds the power of 2 to which
to align. This type is only generated by machine specific
code, which is normally responsible for handling the fill
pattern. The fr_subtype field holds the maximum number of
bytes to skip when aligning, or 0 if there is no maximum. */
rs_align_code,
/* Test for alignment. Like rs_align, but used by several targets
to warn if data is not properly aligned. */
rs_align_test,
/* Org: Fr_offset, fr_symbol: address. 1 variable char: fill
character. */
rs_org,
#ifndef WORKING_DOT_WORD
/* JF: gunpoint */
rs_broken_word,
#endif
/* Machine specific relaxable (or similarly alterable) instruction. */
rs_machine_dependent,
/* .space directive with expression operand that needs to be computed
later. Similar to rs_org, but different.
fr_symbol: operand
1 variable char: fill character */
rs_space,
/* A DWARF leb128 value; only ELF uses this. The subtype is 0 for
unsigned, 1 for signed. */
rs_leb128,
/* Exception frame information which we may be able to optimize. */
rs_cfa,
/* Cross-fragment dwarf2 line number optimization. */
rs_dwarf2dbg
};
typedef enum _relax_state relax_stateT;
/* This type is used in prototypes, so it can't be a type that will be
widened for argument passing. */
typedef unsigned int relax_substateT;
/* Enough bits for address, but still an integer type.
Could be a problem, cross-assembling for 64-bit machines. */
typedef addressT relax_addressT;
struct relax_type
{
/* Forward reach. Signed number. > 0. */
offsetT rlx_forward;
/* Backward reach. Signed number. < 0. */
offsetT rlx_backward;
/* Bytes length of this address. */
unsigned char rlx_length;
/* Next longer relax-state. 0 means there is no 'next' relax-state. */
relax_substateT rlx_more;
};
typedef struct relax_type relax_typeS;
/* main program "as.c" (command arguments etc). */
COMMON unsigned char flag_no_comments; /* -f */
COMMON unsigned char flag_debug; /* -D */
COMMON unsigned char flag_signed_overflow_ok; /* -J */
#ifndef WORKING_DOT_WORD
COMMON unsigned char flag_warn_displacement; /* -K */
#endif
/* True if local symbols should be retained. */
COMMON int flag_keep_locals; /* -L */
/* True if we are assembling in MRI mode. */
COMMON int flag_mri;
/* Should the data section be made read-only and appended to the text
section? */
COMMON unsigned char flag_readonly_data_in_text; /* -R */
/* True if warnings should be inhibited. */
COMMON int flag_no_warnings; /* -W */
/* True if warnings count as errors. */
COMMON int flag_fatal_warnings; /* --fatal-warnings */
/* True if we should attempt to generate output even if non-fatal errors
are detected. */
COMMON unsigned char flag_always_generate_output; /* -Z */
/* This is true if the assembler should output time and space usage. */
COMMON unsigned char flag_print_statistics;
/* True if local absolute symbols are to be stripped. */
COMMON int flag_strip_local_absolute;
/* True if we should generate a traditional format object file. */
COMMON int flag_traditional_format;
/* TRUE if debug sections should be compressed. */
COMMON int flag_compress_debug;
/* TRUE if .note.GNU-stack section with SEC_CODE should be created */
COMMON int flag_execstack;
/* TRUE if .note.GNU-stack section with SEC_CODE should be created */
COMMON int flag_noexecstack;
/* name of emitted object file */
COMMON char *out_file_name;
/* name of file defining extensions to the basic instruction set */
COMMON char *insttbl_file_name;
/* TRUE if we need a second pass. */
COMMON int need_pass_2;
/* TRUE if we should do no relaxing, and
leave lots of padding. */
COMMON int linkrelax;
/* TRUE if we should produce a listing. */
extern int listing;
/* Type of debugging information we should generate. We currently support
stabs, ECOFF, and DWARF2.
NOTE! This means debug information about the assembly source code itself
and _not_ about possible debug information from a high-level language.
This is especially relevant to DWARF2, since the compiler may emit line
number directives that the assembler resolves. */
enum debug_info_type
{
DEBUG_UNSPECIFIED,
DEBUG_NONE,
DEBUG_STABS,
DEBUG_ECOFF,
DEBUG_DWARF,
DEBUG_DWARF2
};
extern enum debug_info_type debug_type;
extern int use_gnu_debug_info_extensions;
COMMON bfd_boolean flag_dwarf_sections;
/* Maximum level of macro nesting. */
extern int max_macro_nest;
/* Verbosity level. */
extern int verbose;
/* Obstack chunk size. Keep large for efficient space use, make small to
increase malloc calls for monitoring memory allocation. */
extern int chunksize;
struct _pseudo_type
{
/* assembler mnemonic, lower case, no '.' */
const char *poc_name;
/* Do the work */
void (*poc_handler) (int);
/* Value to pass to handler */
int poc_val;
};
typedef struct _pseudo_type pseudo_typeS;
#if (__GNUC__ >= 2) && !defined(VMS)
/* for use with -Wformat */
#if __GNUC__ == 2 && __GNUC_MINOR__ < 6
/* Support for double underscores in attribute names was added in gcc
2.6, so avoid them if we are using an earlier version. */
#define __printf__ printf
#define __format__ format
#endif
#define PRINTF_LIKE(FCN) \
void FCN (const char *format, ...) \
__attribute__ ((__format__ (__printf__, 1, 2)))
#define PRINTF_WHERE_LIKE(FCN) \
void FCN (char *file, unsigned int line, const char *format, ...) \
__attribute__ ((__format__ (__printf__, 3, 4)))
#else /* __GNUC__ < 2 || defined(VMS) */
#define PRINTF_LIKE(FCN) void FCN (const char *format, ...)
#define PRINTF_WHERE_LIKE(FCN) void FCN (char *file, \
unsigned int line, \
const char *format, ...)
#endif /* __GNUC__ < 2 || defined(VMS) */
PRINTF_LIKE (as_bad);
PRINTF_LIKE (as_fatal) ATTRIBUTE_NORETURN;
PRINTF_LIKE (as_tsktsk);
PRINTF_LIKE (as_warn);
PRINTF_WHERE_LIKE (as_bad_where);
PRINTF_WHERE_LIKE (as_warn_where);
void as_assert (const char *, int, const char *);
void as_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
void sprint_value (char *, addressT);
int had_errors (void);
int had_warnings (void);
void as_warn_value_out_of_range (char *, offsetT, offsetT, offsetT, char *, unsigned);
void as_bad_value_out_of_range (char *, offsetT, offsetT, offsetT, char *, unsigned);
void print_version_id (void);
char * app_push (void);
char * atof_ieee (char *, int, LITTLENUM_TYPE *);
char * ieee_md_atof (int, char *, int *, bfd_boolean);
char * vax_md_atof (int, char *, int *);
char * input_scrub_include_file (char *, char *);
void input_scrub_insert_line (const char *);
void input_scrub_insert_file (char *);
char * input_scrub_new_file (char *);
char * input_scrub_next_buffer (char **bufp);
size_t do_scrub_chars (size_t (*get) (char *, size_t), char *, size_t);
int gen_to_words (LITTLENUM_TYPE *, int, long);
int had_err (void);
int ignore_input (void);
void cond_finish_check (int);
void cond_exit_macro (int);
int seen_at_least_1_file (void);
void app_pop (char *);
void as_where (char **, unsigned int *);
void bump_line_counters (void);
void do_scrub_begin (int);
void input_scrub_begin (void);
void input_scrub_close (void);
void input_scrub_end (void);
int new_logical_line (char *, int);
int new_logical_line_flags (char *, int, int);
void subsegs_begin (void);
void subseg_change (segT, int);
segT subseg_new (const char *, subsegT);
segT subseg_force_new (const char *, subsegT);
void subseg_set (segT, subsegT);
int subseg_text_p (segT);
int seg_not_empty_p (segT);
void start_dependencies (char *);
void register_dependency (char *);
void print_dependencies (void);
segT subseg_get (const char *, int);
const char *remap_debug_filename (const char *);
void add_debug_prefix_map (const char *);
struct expressionS;
struct fix;
typedef struct symbol symbolS;
typedef struct frag fragS;
/* literal.c */
valueT add_to_literal_pool (symbolS *, valueT, segT, int);
int check_eh_frame (struct expressionS *, unsigned int *);
int eh_frame_estimate_size_before_relax (fragS *);
int eh_frame_relax_frag (fragS *);
void eh_frame_convert_frag (fragS *);
int generic_force_reloc (struct fix *);
#include "expr.h" /* Before targ-*.h */
/* This one starts the chain of target dependant headers. */
#include "targ-env.h"
#ifdef OBJ_MAYBE_ELF
#define IS_ELF (OUTPUT_FLAVOR == bfd_target_elf_flavour)
#else
#ifdef OBJ_ELF
#define IS_ELF 1
#else
#define IS_ELF 0
#endif
#endif
#include "write.h"
#include "frags.h"
#include "hash.h"
#include "read.h"
#include "symbols.h"
#include "tc.h"
#include "obj.h"
#ifdef USE_EMULATIONS
#include "emul.h"
#endif
#include "listing.h"
#ifdef H_TICK_HEX
extern int enable_h_tick_hex;
#endif
#ifdef TC_M68K
/* True if we are assembling in m68k MRI mode. */
COMMON int flag_m68k_mri;
#define DOLLAR_AMBIGU flag_m68k_mri
#else
#define flag_m68k_mri 0
#endif
#ifdef WARN_COMMENTS
COMMON int warn_comment;
COMMON unsigned int found_comment;
COMMON char * found_comment_file;
#endif
#if defined OBJ_ELF || defined OBJ_MAYBE_ELF
/* If .size directive failure should be error or warning. */
COMMON enum
{
size_check_error = 0,
size_check_warning
}
flag_size_check;
#endif
#ifndef DOLLAR_AMBIGU
#define DOLLAR_AMBIGU 0
#endif
#ifndef NUMBERS_WITH_SUFFIX
#define NUMBERS_WITH_SUFFIX 0
#endif
#ifndef LOCAL_LABELS_DOLLAR
#define LOCAL_LABELS_DOLLAR 0
#endif
#ifndef LOCAL_LABELS_FB
#define LOCAL_LABELS_FB 0
#endif
#ifndef LABELS_WITHOUT_COLONS
#define LABELS_WITHOUT_COLONS 0
#endif
#ifndef NO_PSEUDO_DOT
#define NO_PSEUDO_DOT 0
#endif
#ifndef TEXT_SECTION_NAME
#define TEXT_SECTION_NAME ".text"
#define DATA_SECTION_NAME ".data"
#define BSS_SECTION_NAME ".bss"
#endif
#ifndef OCTETS_PER_BYTE_POWER
#define OCTETS_PER_BYTE_POWER 0
#endif
#ifndef OCTETS_PER_BYTE
#define OCTETS_PER_BYTE (1<<OCTETS_PER_BYTE_POWER)
#endif
#if OCTETS_PER_BYTE != (1<<OCTETS_PER_BYTE_POWER)
#error "Octets per byte conflicts with its power-of-two definition!"
#endif
#endif /* GAS */

View File

@ -0,0 +1,52 @@
/* asintl.h - gas-specific header for gettext code.
Copyright 1998, 1999, 2000, 2005, 2007 Free Software Foundation, Inc.
Written by Tom Tromey <tromey@cygnus.com>
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifdef HAVE_LOCALE_H
# ifndef ENABLE_NLS
/* The Solaris version of locale.h always includes libintl.h. If we have
been configured with --disable-nls then ENABLE_NLS will not be defined
and the dummy definitions of bindtextdomain (et al) below will conflict
with the defintions in libintl.h. So we define these values to prevent
the bogus inclusion of libintl.h. */
# define _LIBINTL_H
# define _LIBGETTEXT_H
# endif
# include <locale.h>
#endif
#ifdef ENABLE_NLS
# include <libintl.h>
# define _(String) gettext (String)
# ifdef gettext_noop
# define N_(String) gettext_noop (String)
# else
# define N_(String) (String)
# endif
#else
# define gettext(Msgid) (Msgid)
# define dgettext(Domainname, Msgid) (Msgid)
# define dcgettext(Domainname, Msgid, Category) (Msgid)
# define textdomain(Domainname) while (0) /* nothing */
# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */
# define _(String) (String)
# define N_(String) (String)
#endif

View File

@ -0,0 +1,614 @@
/* atof_generic.c - turn a string of digits into a Flonum
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000,
2001, 2003, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "safe-ctype.h"
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (1)
#endif
#ifdef TRACE
static void flonum_print (const FLONUM_TYPE *);
#endif
#define ASSUME_DECIMAL_MARK_IS_DOT
/***********************************************************************\
* *
* Given a string of decimal digits , with optional decimal *
* mark and optional decimal exponent (place value) of the *
* lowest_order decimal digit: produce a floating point *
* number. The number is 'generic' floating point: our *
* caller will encode it for a specific machine architecture. *
* *
* Assumptions *
* uses base (radix) 2 *
* this machine uses 2's complement binary integers *
* target flonums use " " " " *
* target flonums exponents fit in a long *
* *
\***********************************************************************/
/*
Syntax:
<flonum> ::= <optional-sign> <decimal-number> <optional-exponent>
<optional-sign> ::= '+' | '-' | {empty}
<decimal-number> ::= <integer>
| <integer> <radix-character>
| <integer> <radix-character> <integer>
| <radix-character> <integer>
<optional-exponent> ::= {empty}
| <exponent-character> <optional-sign> <integer>
<integer> ::= <digit> | <digit> <integer>
<digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
<exponent-character> ::= {one character from "string_of_decimal_exponent_marks"}
<radix-character> ::= {one character from "string_of_decimal_marks"}
*/
int
atof_generic (/* return pointer to just AFTER number we read. */
char **address_of_string_pointer,
/* At most one per number. */
const char *string_of_decimal_marks,
const char *string_of_decimal_exponent_marks,
FLONUM_TYPE *address_of_generic_floating_point_number)
{
int return_value; /* 0 means OK. */
char *first_digit;
unsigned int number_of_digits_before_decimal;
unsigned int number_of_digits_after_decimal;
long decimal_exponent;
unsigned int number_of_digits_available;
char digits_sign_char;
/*
* Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent.
* It would be simpler to modify the string, but we don't; just to be nice
* to caller.
* We need to know how many digits we have, so we can allocate space for
* the digits' value.
*/
char *p;
char c;
int seen_significant_digit;
#ifdef ASSUME_DECIMAL_MARK_IS_DOT
gas_assert (string_of_decimal_marks[0] == '.'
&& string_of_decimal_marks[1] == 0);
#define IS_DECIMAL_MARK(c) ((c) == '.')
#else
#define IS_DECIMAL_MARK(c) (0 != strchr (string_of_decimal_marks, (c)))
#endif
first_digit = *address_of_string_pointer;
c = *first_digit;
if (c == '-' || c == '+')
{
digits_sign_char = c;
first_digit++;
}
else
digits_sign_char = '+';
switch (first_digit[0])
{
case 'n':
case 'N':
if (!strncasecmp ("nan", first_digit, 3))
{
address_of_generic_floating_point_number->sign = 0;
address_of_generic_floating_point_number->exponent = 0;
address_of_generic_floating_point_number->leader =
address_of_generic_floating_point_number->low;
*address_of_string_pointer = first_digit + 3;
return 0;
}
break;
case 'i':
case 'I':
if (!strncasecmp ("inf", first_digit, 3))
{
address_of_generic_floating_point_number->sign =
digits_sign_char == '+' ? 'P' : 'N';
address_of_generic_floating_point_number->exponent = 0;
address_of_generic_floating_point_number->leader =
address_of_generic_floating_point_number->low;
first_digit += 3;
if (!strncasecmp ("inity", first_digit, 5))
first_digit += 5;
*address_of_string_pointer = first_digit;
return 0;
}
break;
}
number_of_digits_before_decimal = 0;
number_of_digits_after_decimal = 0;
decimal_exponent = 0;
seen_significant_digit = 0;
for (p = first_digit;
(((c = *p) != '\0')
&& (!c || !IS_DECIMAL_MARK (c))
&& (!c || !strchr (string_of_decimal_exponent_marks, c)));
p++)
{
if (ISDIGIT (c))
{
if (seen_significant_digit || c > '0')
{
++number_of_digits_before_decimal;
seen_significant_digit = 1;
}
else
{
first_digit++;
}
}
else
{
break; /* p -> char after pre-decimal digits. */
}
} /* For each digit before decimal mark. */
#ifndef OLD_FLOAT_READS
/* Ignore trailing 0's after the decimal point. The original code here
* (ifdef'd out) does not do this, and numbers like
* 4.29496729600000000000e+09 (2**31)
* come out inexact for some reason related to length of the digit
* string.
*/
if (c && IS_DECIMAL_MARK (c))
{
unsigned int zeros = 0; /* Length of current string of zeros */
for (p++; (c = *p) && ISDIGIT (c); p++)
{
if (c == '0')
{
zeros++;
}
else
{
number_of_digits_after_decimal += 1 + zeros;
zeros = 0;
}
}
}
#else
if (c && IS_DECIMAL_MARK (c))
{
for (p++;
(((c = *p) != '\0')
&& (!c || !strchr (string_of_decimal_exponent_marks, c)));
p++)
{
if (ISDIGIT (c))
{
/* This may be retracted below. */
number_of_digits_after_decimal++;
if ( /* seen_significant_digit || */ c > '0')
{
seen_significant_digit = TRUE;
}
}
else
{
if (!seen_significant_digit)
{
number_of_digits_after_decimal = 0;
}
break;
}
} /* For each digit after decimal mark. */
}
while (number_of_digits_after_decimal
&& first_digit[number_of_digits_before_decimal
+ number_of_digits_after_decimal] == '0')
--number_of_digits_after_decimal;
#endif
if (flag_m68k_mri)
{
while (c == '_')
c = *++p;
}
if (c && strchr (string_of_decimal_exponent_marks, c))
{
char digits_exponent_sign_char;
c = *++p;
if (flag_m68k_mri)
{
while (c == '_')
c = *++p;
}
if (c && strchr ("+-", c))
{
digits_exponent_sign_char = c;
c = *++p;
}
else
{
digits_exponent_sign_char = '+';
}
for (; (c); c = *++p)
{
if (ISDIGIT (c))
{
decimal_exponent = decimal_exponent * 10 + c - '0';
/*
* BUG! If we overflow here, we lose!
*/
}
else
{
break;
}
}
if (digits_exponent_sign_char == '-')
{
decimal_exponent = -decimal_exponent;
}
}
*address_of_string_pointer = p;
number_of_digits_available =
number_of_digits_before_decimal + number_of_digits_after_decimal;
return_value = 0;
if (number_of_digits_available == 0)
{
address_of_generic_floating_point_number->exponent = 0; /* Not strictly necessary */
address_of_generic_floating_point_number->leader
= -1 + address_of_generic_floating_point_number->low;
address_of_generic_floating_point_number->sign = digits_sign_char;
/* We have just concocted (+/-)0.0E0 */
}
else
{
int count; /* Number of useful digits left to scan. */
LITTLENUM_TYPE *digits_binary_low;
unsigned int precision;
unsigned int maximum_useful_digits;
unsigned int number_of_digits_to_use;
unsigned int more_than_enough_bits_for_digits;
unsigned int more_than_enough_littlenums_for_digits;
unsigned int size_of_digits_in_littlenums;
unsigned int size_of_digits_in_chars;
FLONUM_TYPE power_of_10_flonum;
FLONUM_TYPE digits_flonum;
precision = (address_of_generic_floating_point_number->high
- address_of_generic_floating_point_number->low
+ 1); /* Number of destination littlenums. */
/* Includes guard bits (two littlenums worth) */
maximum_useful_digits = (((precision - 2))
* ( (LITTLENUM_NUMBER_OF_BITS))
* 1000000 / 3321928)
+ 2; /* 2 :: guard digits. */
if (number_of_digits_available > maximum_useful_digits)
{
number_of_digits_to_use = maximum_useful_digits;
}
else
{
number_of_digits_to_use = number_of_digits_available;
}
/* Cast these to SIGNED LONG first, otherwise, on systems with
LONG wider than INT (such as Alpha OSF/1), unsignedness may
cause unexpected results. */
decimal_exponent += ((long) number_of_digits_before_decimal
- (long) number_of_digits_to_use);
more_than_enough_bits_for_digits
= (number_of_digits_to_use * 3321928 / 1000000 + 1);
more_than_enough_littlenums_for_digits
= (more_than_enough_bits_for_digits
/ LITTLENUM_NUMBER_OF_BITS)
+ 2;
/* Compute (digits) part. In "12.34E56" this is the "1234" part.
Arithmetic is exact here. If no digits are supplied then this
part is a 0 valued binary integer. Allocate room to build up
the binary number as littlenums. We want this memory to
disappear when we leave this function. Assume no alignment
problems => (room for n objects) == n * (room for 1
object). */
size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits;
size_of_digits_in_chars = size_of_digits_in_littlenums
* sizeof (LITTLENUM_TYPE);
digits_binary_low = (LITTLENUM_TYPE *)
alloca (size_of_digits_in_chars);
memset ((char *) digits_binary_low, '\0', size_of_digits_in_chars);
/* Digits_binary_low[] is allocated and zeroed. */
/*
* Parse the decimal digits as if * digits_low was in the units position.
* Emit a binary number into digits_binary_low[].
*
* Use a large-precision version of:
* (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit
*/
for (p = first_digit, count = number_of_digits_to_use; count; p++, --count)
{
c = *p;
if (ISDIGIT (c))
{
/*
* Multiply by 10. Assume can never overflow.
* Add this digit to digits_binary_low[].
*/
long carry;
LITTLENUM_TYPE *littlenum_pointer;
LITTLENUM_TYPE *littlenum_limit;
littlenum_limit = digits_binary_low
+ more_than_enough_littlenums_for_digits
- 1;
carry = c - '0'; /* char -> binary */
for (littlenum_pointer = digits_binary_low;
littlenum_pointer <= littlenum_limit;
littlenum_pointer++)
{
long work;
work = carry + 10 * (long) (*littlenum_pointer);
*littlenum_pointer = work & LITTLENUM_MASK;
carry = work >> LITTLENUM_NUMBER_OF_BITS;
}
if (carry != 0)
{
/*
* We have a GROSS internal error.
* This should never happen.
*/
as_fatal (_("failed sanity check"));
}
}
else
{
++count; /* '.' doesn't alter digits used count. */
}
}
/*
* Digits_binary_low[] properly encodes the value of the digits.
* Forget about any high-order littlenums that are 0.
*/
while (digits_binary_low[size_of_digits_in_littlenums - 1] == 0
&& size_of_digits_in_littlenums >= 2)
size_of_digits_in_littlenums--;
digits_flonum.low = digits_binary_low;
digits_flonum.high = digits_binary_low + size_of_digits_in_littlenums - 1;
digits_flonum.leader = digits_flonum.high;
digits_flonum.exponent = 0;
/*
* The value of digits_flonum . sign should not be important.
* We have already decided the output's sign.
* We trust that the sign won't influence the other parts of the number!
* So we give it a value for these reasons:
* (1) courtesy to humans reading/debugging
* these numbers so they don't get excited about strange values
* (2) in future there may be more meaning attached to sign,
* and what was
* harmless noise may become disruptive, ill-conditioned (or worse)
* input.
*/
digits_flonum.sign = '+';
{
/*
* Compute the mantssa (& exponent) of the power of 10.
* If successful, then multiply the power of 10 by the digits
* giving return_binary_mantissa and return_binary_exponent.
*/
LITTLENUM_TYPE *power_binary_low;
int decimal_exponent_is_negative;
/* This refers to the "-56" in "12.34E-56". */
/* FALSE: decimal_exponent is positive (or 0) */
/* TRUE: decimal_exponent is negative */
FLONUM_TYPE temporary_flonum;
LITTLENUM_TYPE *temporary_binary_low;
unsigned int size_of_power_in_littlenums;
unsigned int size_of_power_in_chars;
size_of_power_in_littlenums = precision;
/* Precision has a built-in fudge factor so we get a few guard bits. */
decimal_exponent_is_negative = decimal_exponent < 0;
if (decimal_exponent_is_negative)
{
decimal_exponent = -decimal_exponent;
}
/* From now on: the decimal exponent is > 0. Its sign is separate. */
size_of_power_in_chars = size_of_power_in_littlenums
* sizeof (LITTLENUM_TYPE) + 2;
power_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars);
temporary_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars);
memset ((char *) power_binary_low, '\0', size_of_power_in_chars);
*power_binary_low = 1;
power_of_10_flonum.exponent = 0;
power_of_10_flonum.low = power_binary_low;
power_of_10_flonum.leader = power_binary_low;
power_of_10_flonum.high = power_binary_low + size_of_power_in_littlenums - 1;
power_of_10_flonum.sign = '+';
temporary_flonum.low = temporary_binary_low;
temporary_flonum.high = temporary_binary_low + size_of_power_in_littlenums - 1;
/*
* (power) == 1.
* Space for temporary_flonum allocated.
*/
/*
* ...
*
* WHILE more bits
* DO find next bit (with place value)
* multiply into power mantissa
* OD
*/
{
int place_number_limit;
/* Any 10^(2^n) whose "n" exceeds this */
/* value will fall off the end of */
/* flonum_XXXX_powers_of_ten[]. */
int place_number;
const FLONUM_TYPE *multiplicand; /* -> 10^(2^n) */
place_number_limit = table_size_of_flonum_powers_of_ten;
multiplicand = (decimal_exponent_is_negative
? flonum_negative_powers_of_ten
: flonum_positive_powers_of_ten);
for (place_number = 1;/* Place value of this bit of exponent. */
decimal_exponent;/* Quit when no more 1 bits in exponent. */
decimal_exponent >>= 1, place_number++)
{
if (decimal_exponent & 1)
{
if (place_number > place_number_limit)
{
/* The decimal exponent has a magnitude so great
that our tables can't help us fragment it.
Although this routine is in error because it
can't imagine a number that big, signal an
error as if it is the user's fault for
presenting such a big number. */
return_value = ERROR_EXPONENT_OVERFLOW;
/* quit out of loop gracefully */
decimal_exponent = 0;
}
else
{
#ifdef TRACE
printf ("before multiply, place_number = %d., power_of_10_flonum:\n",
place_number);
flonum_print (&power_of_10_flonum);
(void) putchar ('\n');
#endif
#ifdef TRACE
printf ("multiplier:\n");
flonum_print (multiplicand + place_number);
(void) putchar ('\n');
#endif
flonum_multip (multiplicand + place_number,
&power_of_10_flonum, &temporary_flonum);
#ifdef TRACE
printf ("after multiply:\n");
flonum_print (&temporary_flonum);
(void) putchar ('\n');
#endif
flonum_copy (&temporary_flonum, &power_of_10_flonum);
#ifdef TRACE
printf ("after copy:\n");
flonum_print (&power_of_10_flonum);
(void) putchar ('\n');
#endif
} /* If this bit of decimal_exponent was computable.*/
} /* If this bit of decimal_exponent was set. */
} /* For each bit of binary representation of exponent */
#ifdef TRACE
printf ("after computing power_of_10_flonum:\n");
flonum_print (&power_of_10_flonum);
(void) putchar ('\n');
#endif
}
}
/*
* power_of_10_flonum is power of ten in binary (mantissa) , (exponent).
* It may be the number 1, in which case we don't NEED to multiply.
*
* Multiply (decimal digits) by power_of_10_flonum.
*/
flonum_multip (&power_of_10_flonum, &digits_flonum, address_of_generic_floating_point_number);
/* Assert sign of the number we made is '+'. */
address_of_generic_floating_point_number->sign = digits_sign_char;
}
return return_value;
}
#ifdef TRACE
static void
flonum_print (f)
const FLONUM_TYPE *f;
{
LITTLENUM_TYPE *lp;
char littlenum_format[10];
sprintf (littlenum_format, " %%0%dx", sizeof (LITTLENUM_TYPE) * 2);
#define print_littlenum(LP) (printf (littlenum_format, LP))
printf ("flonum @%p %c e%ld", f, f->sign, f->exponent);
if (f->low < f->high)
for (lp = f->high; lp >= f->low; lp--)
print_littlenum (*lp);
else
for (lp = f->low; lp <= f->high; lp++)
print_littlenum (*lp);
printf ("\n");
fflush (stdout);
}
#endif
/* end of atof_generic.c */

View File

@ -0,0 +1,42 @@
/* bignum.h-arbitrary precision integers
Copyright 1987, 1992, 2003, 2005, 2007 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/***********************************************************************\
* *
* Arbitrary-precision integer arithmetic. *
* For speed, we work in groups of bits, even though this *
* complicates algorithms. *
* Each group of bits is called a 'littlenum'. *
* A bunch of littlenums representing a (possibly large) *
* integer is called a 'bignum'. *
* Bignums are >= 0. *
* *
\***********************************************************************/
#define LITTLENUM_NUMBER_OF_BITS (16)
#define LITTLENUM_RADIX (1 << LITTLENUM_NUMBER_OF_BITS)
#define LITTLENUM_MASK (0xFFFF)
#define LITTLENUM_SHIFT (1)
#define CHARS_PER_LITTLENUM (1 << LITTLENUM_SHIFT)
#ifndef BITS_PER_CHAR
#define BITS_PER_CHAR (8)
#endif
typedef unsigned short LITTLENUM_TYPE;

View File

@ -0,0 +1,48 @@
/* bit_fix.h
Copyright 1987, 1992, 2000, 2001, 2003, 2005, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* The bit_fix was implemented to support machines that need variables
to be inserted in bitfields other than 1, 2 and 4 bytes.
Furthermore it gives us a possibility to mask in bits in the symbol
when it's fixed in the objectcode and check the symbols limits.
The or-mask is used to set the huffman bits in displacements for the
ns32k port.
The acbi, addqi, movqi, cmpqi instruction requires an assembler that
can handle bitfields. Ie. handle an expression, evaluate it and insert
the result in some bitfield. (eg: 5 bits in a short field of an opcode). */
#ifndef __bit_fix_h__
#define __bit_fix_h__
struct bit_fix {
int fx_bit_size; /* Length of bitfield */
int fx_bit_offset; /* Bit offset to bitfield */
long fx_bit_base; /* Where do we apply the bitfix.
If this is zero, default is assumed. */
long fx_bit_base_adj; /* Adjustment of base */
long fx_bit_max; /* Signextended max for bitfield */
long fx_bit_min; /* Signextended min for bitfield */
long fx_bit_add; /* Or mask, used for huffman prefix */
};
typedef struct bit_fix bit_fixS;
#endif /* __bit_fix_h__ */

View File

@ -0,0 +1,117 @@
/* compress-debug.c - compress debug sections
Copyright 2010 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "config.h"
#include <stdio.h>
#include "ansidecl.h"
#include "compress-debug.h"
#ifdef HAVE_ZLIB_H
#include <zlib.h>
#endif
/* Initialize the compression engine. */
struct z_stream_s *
compress_init (void)
{
#ifndef HAVE_ZLIB_H
return NULL;
#else
static struct z_stream_s strm;
strm.zalloc = NULL;
strm.zfree = NULL;
strm.opaque = NULL;
deflateInit (&strm, Z_DEFAULT_COMPRESSION);
return &strm;
#endif /* HAVE_ZLIB_H */
}
/* Stream the contents of a frag to the compression engine. Output
from the engine goes into the current frag on the obstack. */
int
compress_data (struct z_stream_s *strm ATTRIBUTE_UNUSED,
const char **next_in ATTRIBUTE_UNUSED,
int *avail_in ATTRIBUTE_UNUSED,
char **next_out ATTRIBUTE_UNUSED,
int *avail_out ATTRIBUTE_UNUSED)
{
#ifndef HAVE_ZLIB_H
return -1;
#else
int out_size = 0;
int x;
strm->next_in = (Bytef *) (*next_in);
strm->avail_in = *avail_in;
strm->next_out = (Bytef *) (*next_out);
strm->avail_out = *avail_out;
x = deflate (strm, Z_NO_FLUSH);
if (x != Z_OK)
return -1;
out_size = *avail_out - strm->avail_out;
*next_in = (char *) (strm->next_in);
*avail_in = strm->avail_in;
*next_out = (char *) (strm->next_out);
*avail_out = strm->avail_out;
return out_size;
#endif /* HAVE_ZLIB_H */
}
/* Finish the compression and consume the remaining compressed output.
Returns -1 for error, 0 when done, 1 when more output buffer is
needed. */
int
compress_finish (struct z_stream_s *strm ATTRIBUTE_UNUSED,
char **next_out ATTRIBUTE_UNUSED,
int *avail_out ATTRIBUTE_UNUSED,
int *out_size ATTRIBUTE_UNUSED)
{
#ifndef HAVE_ZLIB_H
return -1;
#else
int x;
strm->avail_in = 0;
strm->next_out = (Bytef *) (*next_out);
strm->avail_out = *avail_out;
x = deflate (strm, Z_FINISH);
*out_size = *avail_out - strm->avail_out;
*next_out = (char *) (strm->next_out);
*avail_out = strm->avail_out;
if (x == Z_STREAM_END)
{
deflateEnd (strm);
return 0;
}
if (strm->avail_out != 0)
return -1;
return 1;
#endif /* HAVE_ZLIB_H */
}

View File

@ -0,0 +1,39 @@
/* compress-debug.h - Header file for compressed debug sections.
Copyright 2010 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef COMPRESS_DEBUG_H
#define COMPRESS_DEBUG_H
struct z_stream_s;
/* Initialize the compression engine. */
extern struct z_stream_s *
compress_init (void);
/* Stream the contents of a frag to the compression engine. Output
from the engine goes into the current frag on the obstack. */
extern int
compress_data (struct z_stream_s *, const char **, int *, char **, int *);
/* Finish the compression and consume the remaining compressed output. */
extern int
compress_finish (struct z_stream_s *, char **, int *, int *);
#endif /* COMPRESS_DEBUG_H */

View File

@ -0,0 +1,577 @@
/* cond.c - conditional assembly pseudo-ops, and .include
Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 2000, 2001, 2002,
2003, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "sb.h"
#include "macro.h"
#include "obstack.h"
/* This is allocated to grow and shrink as .ifdef/.endif pairs are
scanned. */
struct obstack cond_obstack;
struct file_line {
char *file;
unsigned int line;
};
/* We push one of these structures for each .if, and pop it at the
.endif. */
struct conditional_frame {
/* The source file & line number of the "if". */
struct file_line if_file_line;
/* The source file & line of the "else". */
struct file_line else_file_line;
/* The previous conditional. */
struct conditional_frame *previous_cframe;
/* Have we seen an else yet? */
int else_seen;
/* Whether we are currently ignoring input. */
int ignoring;
/* Whether a conditional at a higher level is ignoring input.
Set also when a branch of an "if .. elseif .." tree has matched
to prevent further matches. */
int dead_tree;
/* Macro nesting level at which this conditional was created. */
int macro_nest;
};
static void initialize_cframe (struct conditional_frame *cframe);
static char *get_mri_string (int, int *);
static struct conditional_frame *current_cframe = NULL;
/* Performs the .ifdef (test_defined == 1) and
the .ifndef (test_defined == 0) pseudo op. */
void
s_ifdef (int test_defined)
{
/* Points to name of symbol. */
char *name;
/* Points to symbol. */
symbolS *symbolP;
struct conditional_frame cframe;
char c;
/* Leading whitespace is part of operand. */
SKIP_WHITESPACE ();
name = input_line_pointer;
if (!is_name_beginner (*name))
{
as_bad (_("invalid identifier for \".ifdef\""));
obstack_1grow (&cond_obstack, 0);
ignore_rest_of_line ();
return;
}
c = get_symbol_end ();
symbolP = symbol_find (name);
*input_line_pointer = c;
initialize_cframe (&cframe);
if (cframe.dead_tree)
cframe.ignoring = 1;
else
{
int is_defined;
/* Use the same definition of 'defined' as .equiv so that a symbol
which has been referenced but not yet given a value/address is
considered to be undefined. */
is_defined =
symbolP != NULL
&& (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
&& S_GET_SEGMENT (symbolP) != reg_section;
cframe.ignoring = ! (test_defined ^ is_defined);
}
current_cframe = ((struct conditional_frame *)
obstack_copy (&cond_obstack, &cframe,
sizeof (cframe)));
if (LISTING_SKIP_COND ()
&& cframe.ignoring
&& (cframe.previous_cframe == NULL
|| ! cframe.previous_cframe->ignoring))
listing_list (2);
demand_empty_rest_of_line ();
}
void
s_if (int arg)
{
expressionS operand;
struct conditional_frame cframe;
int t;
char *stop = NULL;
char stopc;
if (flag_mri)
stop = mri_comment_field (&stopc);
/* Leading whitespace is part of operand. */
SKIP_WHITESPACE ();
if (current_cframe != NULL && current_cframe->ignoring)
{
operand.X_add_number = 0;
while (! is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
}
else
{
expression_and_evaluate (&operand);
if (operand.X_op != O_constant)
as_bad (_("non-constant expression in \".if\" statement"));
}
switch ((operatorT) arg)
{
case O_eq: t = operand.X_add_number == 0; break;
case O_ne: t = operand.X_add_number != 0; break;
case O_lt: t = operand.X_add_number < 0; break;
case O_le: t = operand.X_add_number <= 0; break;
case O_ge: t = operand.X_add_number >= 0; break;
case O_gt: t = operand.X_add_number > 0; break;
default:
abort ();
return;
}
/* If the above error is signaled, this will dispatch
using an undefined result. No big deal. */
initialize_cframe (&cframe);
cframe.ignoring = cframe.dead_tree || ! t;
current_cframe = ((struct conditional_frame *)
obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
if (LISTING_SKIP_COND ()
&& cframe.ignoring
&& (cframe.previous_cframe == NULL
|| ! cframe.previous_cframe->ignoring))
listing_list (2);
if (flag_mri)
mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
}
/* Performs the .ifb (test_blank == 1) and
the .ifnb (test_blank == 0) pseudo op. */
void
s_ifb (int test_blank)
{
struct conditional_frame cframe;
initialize_cframe (&cframe);
if (cframe.dead_tree)
cframe.ignoring = 1;
else
{
int is_eol;
SKIP_WHITESPACE ();
is_eol = is_end_of_line[(unsigned char) *input_line_pointer];
cframe.ignoring = (test_blank == !is_eol);
}
current_cframe = ((struct conditional_frame *)
obstack_copy (&cond_obstack, &cframe,
sizeof (cframe)));
if (LISTING_SKIP_COND ()
&& cframe.ignoring
&& (cframe.previous_cframe == NULL
|| ! cframe.previous_cframe->ignoring))
listing_list (2);
ignore_rest_of_line ();
}
/* Get a string for the MRI IFC or IFNC pseudo-ops. */
static char *
get_mri_string (int terminator, int *len)
{
char *ret;
char *s;
SKIP_WHITESPACE ();
s = ret = input_line_pointer;
if (*input_line_pointer == '\'')
{
++s;
++input_line_pointer;
while (! is_end_of_line[(unsigned char) *input_line_pointer])
{
*s++ = *input_line_pointer++;
if (s[-1] == '\'')
{
if (*input_line_pointer != '\'')
break;
++input_line_pointer;
}
}
SKIP_WHITESPACE ();
}
else
{
while (*input_line_pointer != terminator
&& ! is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
s = input_line_pointer;
while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
--s;
}
*len = s - ret;
return ret;
}
/* The MRI IFC and IFNC pseudo-ops. */
void
s_ifc (int arg)
{
char *stop = NULL;
char stopc;
char *s1, *s2;
int len1, len2;
int res;
struct conditional_frame cframe;
if (flag_mri)
stop = mri_comment_field (&stopc);
s1 = get_mri_string (',', &len1);
if (*input_line_pointer != ',')
as_bad (_("bad format for ifc or ifnc"));
else
++input_line_pointer;
s2 = get_mri_string (';', &len2);
res = len1 == len2 && strncmp (s1, s2, len1) == 0;
initialize_cframe (&cframe);
cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
current_cframe = ((struct conditional_frame *)
obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
if (LISTING_SKIP_COND ()
&& cframe.ignoring
&& (cframe.previous_cframe == NULL
|| ! cframe.previous_cframe->ignoring))
listing_list (2);
if (flag_mri)
mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
}
void
s_elseif (int arg)
{
if (current_cframe == NULL)
{
as_bad (_("\".elseif\" without matching \".if\""));
}
else if (current_cframe->else_seen)
{
as_bad (_("\".elseif\" after \".else\""));
as_bad_where (current_cframe->else_file_line.file,
current_cframe->else_file_line.line,
_("here is the previous \".else\""));
as_bad_where (current_cframe->if_file_line.file,
current_cframe->if_file_line.line,
_("here is the previous \".if\""));
}
else
{
as_where (&current_cframe->else_file_line.file,
&current_cframe->else_file_line.line);
current_cframe->dead_tree |= !current_cframe->ignoring;
current_cframe->ignoring = current_cframe->dead_tree;
}
if (current_cframe == NULL || current_cframe->ignoring)
{
while (! is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
if (current_cframe == NULL)
return;
}
else
{
expressionS operand;
int t;
/* Leading whitespace is part of operand. */
SKIP_WHITESPACE ();
expression_and_evaluate (&operand);
if (operand.X_op != O_constant)
as_bad (_("non-constant expression in \".elseif\" statement"));
switch ((operatorT) arg)
{
case O_eq: t = operand.X_add_number == 0; break;
case O_ne: t = operand.X_add_number != 0; break;
case O_lt: t = operand.X_add_number < 0; break;
case O_le: t = operand.X_add_number <= 0; break;
case O_ge: t = operand.X_add_number >= 0; break;
case O_gt: t = operand.X_add_number > 0; break;
default:
abort ();
return;
}
current_cframe->ignoring = current_cframe->dead_tree || ! t;
}
if (LISTING_SKIP_COND ()
&& (current_cframe->previous_cframe == NULL
|| ! current_cframe->previous_cframe->ignoring))
{
if (! current_cframe->ignoring)
listing_list (1);
else
listing_list (2);
}
demand_empty_rest_of_line ();
}
void
s_endif (int arg ATTRIBUTE_UNUSED)
{
struct conditional_frame *hold;
if (current_cframe == NULL)
{
as_bad (_("\".endif\" without \".if\""));
}
else
{
if (LISTING_SKIP_COND ()
&& current_cframe->ignoring
&& (current_cframe->previous_cframe == NULL
|| ! current_cframe->previous_cframe->ignoring))
listing_list (1);
hold = current_cframe;
current_cframe = current_cframe->previous_cframe;
obstack_free (&cond_obstack, hold);
} /* if one pop too many */
if (flag_mri)
{
while (! is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
}
demand_empty_rest_of_line ();
}
void
s_else (int arg ATTRIBUTE_UNUSED)
{
if (current_cframe == NULL)
{
as_bad (_("\".else\" without matching \".if\""));
}
else if (current_cframe->else_seen)
{
as_bad (_("duplicate \".else\""));
as_bad_where (current_cframe->else_file_line.file,
current_cframe->else_file_line.line,
_("here is the previous \".else\""));
as_bad_where (current_cframe->if_file_line.file,
current_cframe->if_file_line.line,
_("here is the previous \".if\""));
}
else
{
as_where (&current_cframe->else_file_line.file,
&current_cframe->else_file_line.line);
current_cframe->ignoring =
current_cframe->dead_tree | !current_cframe->ignoring;
if (LISTING_SKIP_COND ()
&& (current_cframe->previous_cframe == NULL
|| ! current_cframe->previous_cframe->ignoring))
{
if (! current_cframe->ignoring)
listing_list (1);
else
listing_list (2);
}
current_cframe->else_seen = 1;
}
if (flag_mri)
{
while (! is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
}
demand_empty_rest_of_line ();
}
void
s_ifeqs (int arg)
{
char *s1, *s2;
int len1, len2;
int res;
struct conditional_frame cframe;
s1 = demand_copy_C_string (&len1);
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
as_bad (_(".ifeqs syntax error"));
ignore_rest_of_line ();
return;
}
++input_line_pointer;
s2 = demand_copy_C_string (&len2);
res = len1 == len2 && strncmp (s1, s2, len1) == 0;
initialize_cframe (&cframe);
cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
current_cframe = ((struct conditional_frame *)
obstack_copy (&cond_obstack, &cframe, sizeof (cframe)));
if (LISTING_SKIP_COND ()
&& cframe.ignoring
&& (cframe.previous_cframe == NULL
|| ! cframe.previous_cframe->ignoring))
listing_list (2);
demand_empty_rest_of_line ();
}
int
ignore_input (void)
{
char *s;
s = input_line_pointer;
if (NO_PSEUDO_DOT || flag_m68k_mri)
{
if (s[-1] != '.')
--s;
}
else
{
if (s[-1] != '.')
return (current_cframe != NULL) && (current_cframe->ignoring);
}
/* We cannot ignore certain pseudo ops. */
if (((s[0] == 'i'
|| s[0] == 'I')
&& (!strncasecmp (s, "if", 2)
|| !strncasecmp (s, "ifdef", 5)
|| !strncasecmp (s, "ifndef", 6)))
|| ((s[0] == 'e'
|| s[0] == 'E')
&& (!strncasecmp (s, "else", 4)
|| !strncasecmp (s, "endif", 5)
|| !strncasecmp (s, "endc", 4))))
return 0;
return (current_cframe != NULL) && (current_cframe->ignoring);
}
static void
initialize_cframe (struct conditional_frame *cframe)
{
memset (cframe, 0, sizeof (*cframe));
as_where (&cframe->if_file_line.file,
&cframe->if_file_line.line);
cframe->previous_cframe = current_cframe;
cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
cframe->macro_nest = macro_nest;
}
/* Give an error if a conditional is unterminated inside a macro or
the assembly as a whole. If NEST is non negative, we are being
called because of the end of a macro expansion. If NEST is
negative, we are being called at the of the input files. */
void
cond_finish_check (int nest)
{
if (current_cframe != NULL && current_cframe->macro_nest >= nest)
{
if (nest >= 0)
as_bad (_("end of macro inside conditional"));
else
as_bad (_("end of file inside conditional"));
as_bad_where (current_cframe->if_file_line.file,
current_cframe->if_file_line.line,
_("here is the start of the unterminated conditional"));
if (current_cframe->else_seen)
as_bad_where (current_cframe->else_file_line.file,
current_cframe->else_file_line.line,
_("here is the \"else\" of the unterminated conditional"));
}
}
/* This function is called when we exit out of a macro. We assume
that any conditionals which began within the macro are correctly
nested, and just pop them off the stack. */
void
cond_exit_macro (int nest)
{
while (current_cframe != NULL && current_cframe->macro_nest >= nest)
{
struct conditional_frame *hold;
hold = current_cframe;
current_cframe = current_cframe->previous_cframe;
obstack_free (&cond_obstack, hold);
}
}

View File

@ -0,0 +1,363 @@
/* config.h. Generated from config.in by configure. */
/* config.in. Generated from configure.in by autoheader. */
/* Check that config.h is #included before system headers
(this works only for glibc, but that should be enough). */
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__CONFIG_H__)
# error config.h must be #included before system headers
#endif
#define __CONFIG_H__ 1
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
/* Define if using AIX 5.2 value for C_WEAKEXT. */
/* #undef AIX_WEAK_SUPPORT */
/* assert broken? */
/* #undef BROKEN_ASSERT */
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems.
*/
/* #undef CRAY_STACKSEG_END */
/* Compiling cross-assembler? */
/* #undef CROSS_COMPILE */
/* Define to 1 if using `alloca.c'. */
/* #undef C_ALLOCA */
/* Default architecture. */
#define DEFAULT_ARCH "i386"
/* Default CRIS architecture. */
/* #undef DEFAULT_CRIS_ARCH */
/* Default emulation. */
#define DEFAULT_EMULATION ""
/* Supported emulations. */
#define EMULATIONS
/* Define if you want run-time sanity checks. */
/* #undef ENABLE_CHECKING */
/* Define to 1 if translation of program messages to the user's native
language is requested. */
/* #undef ENABLE_NLS */
/* Define to 1 if you have `alloca', as a function or macro. */
#define HAVE_ALLOCA 1
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
*/
/* #undef HAVE_ALLOCA_H */
/* Define to 1 if you have the declaration of `free', and to 0 if you don't.
*/
#define HAVE_DECL_FREE 1
/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't.
*/
#define HAVE_DECL_GETENV 1
/* Is the prototype for getopt in <unistd.h> in the expected format? */
#define HAVE_DECL_GETOPT 1
/* Define to 1 if you have the declaration of `malloc', and to 0 if you don't.
*/
#define HAVE_DECL_MALLOC 1
/* Define to 1 if you have the declaration of `mempcpy', and to 0 if you
don't. */
#define HAVE_DECL_MEMPCPY 0
/* Define to 1 if you have the declaration of `realloc', and to 0 if you
don't. */
#define HAVE_DECL_REALLOC 1
/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't.
*/
#define HAVE_DECL_STPCPY 0
/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't.
*/
#define HAVE_DECL_STRSTR 1
/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
don't. */
#define HAVE_DECL_VSNPRINTF 1
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define if your <locale.h> file defines LC_MESSAGES. */
/* #undef HAVE_LC_MESSAGES */
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `remove' function. */
#define HAVE_REMOVE
/* Define to 1 if you have the `sbrk' function. */
/* #undef HAVE_SBRK */
/* Define to 1 if you have the `setlocale' function. */
#define HAVE_SETLOCALE 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define if <sys/stat.h> has struct stat.st_mtim.tv_nsec */
/* #undef HAVE_ST_MTIM_TV_NSEC */
/* Define if <sys/stat.h> has struct stat.st_mtim.tv_sec */
/* #undef HAVE_ST_MTIM_TV_SEC */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1
/* Define if <time.h> has struct tm.tm_gmtoff. */
/* #undef HAVE_TM_GMTOFF */
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `unlink' function. */
#define HAVE_UNLINK 1
/* Define to 1 if you have the <zlib.h> header file. */
#define HAVE_ZLIB_H 1
/* Using i386 COFF? */
#define I386COFF 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Using m68k COFF? */
/* #undef M68KCOFF */
/* Using m88k COFF? */
/* #undef M88KCOFF */
/* Default CPU for MIPS targets. */
/* #undef MIPS_CPU_STRING_DEFAULT */
/* Generate 64-bit code by default on MIPS targets. */
/* #undef MIPS_DEFAULT_64BIT */
/* Choose a default ABI for MIPS targets. */
/* #undef MIPS_DEFAULT_ABI */
/* Define if environ is not declared in system header files. */
/* #undef NEED_DECLARATION_ENVIRON */
/* Define if errno is not declared in system header files. */
/* #undef NEED_DECLARATION_ERRNO */
/* Define if ffs is not declared in system header files. */
#define NEED_DECLARATION_FFS 1
/* Define if free is not declared in system header files. */
/* #undef NEED_DECLARATION_FREE */
/* Define if malloc is not declared in system header files. */
/* #undef NEED_DECLARATION_MALLOC */
/* Define if sbrk is not declared in system header files. */
#define NEED_DECLARATION_SBRK 1
/* Define if strstr is not declared in system header files. */
/* #undef NEED_DECLARATION_STRSTR */
/* a.out support? */
/* #undef OBJ_MAYBE_AOUT */
/* b.out support? */
/* #undef OBJ_MAYBE_BOUT */
/* COFF support? */
/* #undef OBJ_MAYBE_COFF */
/* ECOFF support? */
/* #undef OBJ_MAYBE_ECOFF */
/* ELF support? */
/* #undef OBJ_MAYBE_ELF */
/* generic support? */
/* #undef OBJ_MAYBE_GENERIC */
/* SOM support? */
/* #undef OBJ_MAYBE_SOM */
/* Name of package */
#define PACKAGE "gas"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define if defaulting to ELF on SCO 5. */
/* #undef SCO_ELF */
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at runtime.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
/* #undef STACK_DIRECTION */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Using strict COFF? */
/* #undef STRICTCOFF */
/* Define if you can safely include both <string.h> and <strings.h>. */
#define STRING_WITH_STRINGS 1
/* Target alias. */
#define TARGET_ALIAS "mingw32"
/* Define as 1 if big endian. */
/* #undef TARGET_BYTES_BIG_ENDIAN */
/* Canonical target. */
#define TARGET_CANONICAL "i686-pc-mingw32"
/* Target CPU. */
#define TARGET_CPU "i686"
/* Target OS. */
#define TARGET_OS "mingw32"
/* Define if default target is PowerPC Solaris. */
/* #undef TARGET_SOLARIS_COMMENT */
/* Define if target is Symbian OS. */
/* #undef TARGET_SYMBIAN */
/* Target vendor. */
#define TARGET_VENDOR "pc"
/* Use b modifier when opening binary files? */
#define USE_BINARY_FOPEN 1
/* Use emulation support? */
/* #undef USE_EMULATIONS */
/* Allow use of E_MIPS_ABI_O32 on MIPS targets. */
/* #undef USE_E_MIPS_ABI_O32 */
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
/* Using cgen code? */
/* #undef USING_CGEN */
/* Version number of package */
#define VERSION "2.24"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* # undef WORDS_BIGENDIAN */
# endif
#endif
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */
/* #undef YYTEXT_POINTER */
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif

View File

@ -0,0 +1,813 @@
/* atof_ieee.c - turn a Flonum into an IEEE floating point number
Copyright 1987, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001, 2005,
2007, 2009 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
/* Flonums returned here. */
extern FLONUM_TYPE generic_floating_point_number;
extern const char EXP_CHARS[];
/* Precision in LittleNums. */
/* Don't count the gap in the m68k extended precision format. */
#define MAX_PRECISION 5
#define F_PRECISION 2
#define D_PRECISION 4
#define X_PRECISION 5
#define P_PRECISION 5
/* Length in LittleNums of guard bits. */
#define GUARD 2
#ifndef TC_LARGEST_EXPONENT_IS_NORMAL
#define TC_LARGEST_EXPONENT_IS_NORMAL(PRECISION) 0
#endif
static const unsigned long mask[] =
{
0x00000000,
0x00000001,
0x00000003,
0x00000007,
0x0000000f,
0x0000001f,
0x0000003f,
0x0000007f,
0x000000ff,
0x000001ff,
0x000003ff,
0x000007ff,
0x00000fff,
0x00001fff,
0x00003fff,
0x00007fff,
0x0000ffff,
0x0001ffff,
0x0003ffff,
0x0007ffff,
0x000fffff,
0x001fffff,
0x003fffff,
0x007fffff,
0x00ffffff,
0x01ffffff,
0x03ffffff,
0x07ffffff,
0x0fffffff,
0x1fffffff,
0x3fffffff,
0x7fffffff,
0xffffffff,
};
static int bits_left_in_littlenum;
static int littlenums_left;
static LITTLENUM_TYPE *littlenum_pointer;
static int
next_bits (int number_of_bits)
{
int return_value;
if (!littlenums_left)
return 0;
if (number_of_bits >= bits_left_in_littlenum)
{
return_value = mask[bits_left_in_littlenum] & *littlenum_pointer;
number_of_bits -= bits_left_in_littlenum;
return_value <<= number_of_bits;
if (--littlenums_left)
{
bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
--littlenum_pointer;
return_value |=
(*littlenum_pointer >> bits_left_in_littlenum)
& mask[number_of_bits];
}
}
else
{
bits_left_in_littlenum -= number_of_bits;
return_value =
mask[number_of_bits] & (*littlenum_pointer >> bits_left_in_littlenum);
}
return return_value;
}
/* Num had better be less than LITTLENUM_NUMBER_OF_BITS. */
static void
unget_bits (int num)
{
if (!littlenums_left)
{
++littlenum_pointer;
++littlenums_left;
bits_left_in_littlenum = num;
}
else if (bits_left_in_littlenum + num > LITTLENUM_NUMBER_OF_BITS)
{
bits_left_in_littlenum =
num - (LITTLENUM_NUMBER_OF_BITS - bits_left_in_littlenum);
++littlenum_pointer;
++littlenums_left;
}
else
bits_left_in_littlenum += num;
}
static void
make_invalid_floating_point_number (LITTLENUM_TYPE *words)
{
as_bad (_("cannot create floating-point number"));
/* Zero the leftmost bit. */
words[0] = (LITTLENUM_TYPE) ((unsigned) -1) >> 1;
words[1] = (LITTLENUM_TYPE) -1;
words[2] = (LITTLENUM_TYPE) -1;
words[3] = (LITTLENUM_TYPE) -1;
words[4] = (LITTLENUM_TYPE) -1;
words[5] = (LITTLENUM_TYPE) -1;
}
/* Warning: This returns 16-bit LITTLENUMs. It is up to the caller to
figure out any alignment problems and to conspire for the
bytes/word to be emitted in the right order. Bigendians beware! */
/* Note that atof-ieee always has X and P precisions enabled. it is up
to md_atof to filter them out if the target machine does not support
them. */
/* Returns pointer past text consumed. */
char *
atof_ieee (char *str, /* Text to convert to binary. */
int what_kind, /* 'd', 'f', 'x', 'p'. */
LITTLENUM_TYPE *words) /* Build the binary here. */
{
/* Extra bits for zeroed low-order bits.
The 1st MAX_PRECISION are zeroed, the last contain flonum bits. */
static LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD];
char *return_value;
/* Number of 16-bit words in the format. */
int precision;
long exponent_bits;
FLONUM_TYPE save_gen_flonum;
/* We have to save the generic_floating_point_number because it
contains storage allocation about the array of LITTLENUMs where
the value is actually stored. We will allocate our own array of
littlenums below, but have to restore the global one on exit. */
save_gen_flonum = generic_floating_point_number;
return_value = str;
generic_floating_point_number.low = bits + MAX_PRECISION;
generic_floating_point_number.high = NULL;
generic_floating_point_number.leader = NULL;
generic_floating_point_number.exponent = 0;
generic_floating_point_number.sign = '\0';
/* Use more LittleNums than seems necessary: the highest flonum may
have 15 leading 0 bits, so could be useless. */
memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION);
switch (what_kind)
{
case 'f':
case 'F':
case 's':
case 'S':
precision = F_PRECISION;
exponent_bits = 8;
break;
case 'd':
case 'D':
case 'r':
case 'R':
precision = D_PRECISION;
exponent_bits = 11;
break;
case 'x':
case 'X':
case 'e':
case 'E':
precision = X_PRECISION;
exponent_bits = 15;
break;
case 'p':
case 'P':
precision = P_PRECISION;
exponent_bits = -1;
break;
default:
make_invalid_floating_point_number (words);
return (NULL);
}
generic_floating_point_number.high
= generic_floating_point_number.low + precision - 1 + GUARD;
if (atof_generic (&return_value, ".", EXP_CHARS,
&generic_floating_point_number))
{
make_invalid_floating_point_number (words);
return NULL;
}
gen_to_words (words, precision, exponent_bits);
/* Restore the generic_floating_point_number's storage alloc (and
everything else). */
generic_floating_point_number = save_gen_flonum;
return return_value;
}
/* Turn generic_floating_point_number into a real float/double/extended. */
int
gen_to_words (LITTLENUM_TYPE *words, int precision, long exponent_bits)
{
int return_value = 0;
long exponent_1;
long exponent_2;
long exponent_3;
long exponent_4;
int exponent_skippage;
LITTLENUM_TYPE word1;
LITTLENUM_TYPE *lp;
LITTLENUM_TYPE *words_end;
words_end = words + precision;
#ifdef TC_M68K
if (precision == X_PRECISION)
/* On the m68k the extended precision format has a gap of 16 bits
between the exponent and the mantissa. */
words_end++;
#endif
if (generic_floating_point_number.low > generic_floating_point_number.leader)
{
/* 0.0e0 seen. */
if (generic_floating_point_number.sign == '+')
words[0] = 0x0000;
else
words[0] = 0x8000;
memset (&words[1], '\0',
(words_end - words - 1) * sizeof (LITTLENUM_TYPE));
return return_value;
}
/* NaN: Do the right thing. */
if (generic_floating_point_number.sign == 0)
{
if (TC_LARGEST_EXPONENT_IS_NORMAL (precision))
as_warn (_("NaNs are not supported by this target\n"));
if (precision == F_PRECISION)
{
words[0] = 0x7fff;
words[1] = 0xffff;
}
else if (precision == X_PRECISION)
{
#ifdef TC_M68K
words[0] = 0x7fff;
words[1] = 0;
words[2] = 0xffff;
words[3] = 0xffff;
words[4] = 0xffff;
words[5] = 0xffff;
#else /* ! TC_M68K */
#ifdef TC_I386
words[0] = 0xffff;
words[1] = 0xc000;
words[2] = 0;
words[3] = 0;
words[4] = 0;
#else /* ! TC_I386 */
abort ();
#endif /* ! TC_I386 */
#endif /* ! TC_M68K */
}
else
{
words[0] = 0x7fff;
words[1] = 0xffff;
words[2] = 0xffff;
words[3] = 0xffff;
}
return return_value;
}
else if (generic_floating_point_number.sign == 'P')
{
if (TC_LARGEST_EXPONENT_IS_NORMAL (precision))
as_warn (_("Infinities are not supported by this target\n"));
/* +INF: Do the right thing. */
if (precision == F_PRECISION)
{
words[0] = 0x7f80;
words[1] = 0;
}
else if (precision == X_PRECISION)
{
#ifdef TC_M68K
words[0] = 0x7fff;
words[1] = 0;
words[2] = 0;
words[3] = 0;
words[4] = 0;
words[5] = 0;
#else /* ! TC_M68K */
#ifdef TC_I386
words[0] = 0x7fff;
words[1] = 0x8000;
words[2] = 0;
words[3] = 0;
words[4] = 0;
#else /* ! TC_I386 */
abort ();
#endif /* ! TC_I386 */
#endif /* ! TC_M68K */
}
else
{
words[0] = 0x7ff0;
words[1] = 0;
words[2] = 0;
words[3] = 0;
}
return return_value;
}
else if (generic_floating_point_number.sign == 'N')
{
if (TC_LARGEST_EXPONENT_IS_NORMAL (precision))
as_warn (_("Infinities are not supported by this target\n"));
/* Negative INF. */
if (precision == F_PRECISION)
{
words[0] = 0xff80;
words[1] = 0x0;
}
else if (precision == X_PRECISION)
{
#ifdef TC_M68K
words[0] = 0xffff;
words[1] = 0;
words[2] = 0;
words[3] = 0;
words[4] = 0;
words[5] = 0;
#else /* ! TC_M68K */
#ifdef TC_I386
words[0] = 0xffff;
words[1] = 0x8000;
words[2] = 0;
words[3] = 0;
words[4] = 0;
#else /* ! TC_I386 */
abort ();
#endif /* ! TC_I386 */
#endif /* ! TC_M68K */
}
else
{
words[0] = 0xfff0;
words[1] = 0x0;
words[2] = 0x0;
words[3] = 0x0;
}
return return_value;
}
/* The floating point formats we support have:
Bit 15 is sign bit.
Bits 14:n are excess-whatever exponent.
Bits n-1:0 (if any) are most significant bits of fraction.
Bits 15:0 of the next word(s) are the next most significant bits.
So we need: number of bits of exponent, number of bits of
mantissa. */
bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
littlenum_pointer = generic_floating_point_number.leader;
littlenums_left = (1
+ generic_floating_point_number.leader
- generic_floating_point_number.low);
/* Seek (and forget) 1st significant bit. */
for (exponent_skippage = 0; !next_bits (1); ++exponent_skippage);
exponent_1 = (generic_floating_point_number.exponent
+ generic_floating_point_number.leader
+ 1
- generic_floating_point_number.low);
/* Radix LITTLENUM_RADIX, point just higher than
generic_floating_point_number.leader. */
exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
/* Radix 2. */
exponent_3 = exponent_2 - exponent_skippage;
/* Forget leading zeros, forget 1st bit. */
exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2);
/* Offset exponent. */
lp = words;
/* Word 1. Sign, exponent and perhaps high bits. */
word1 = ((generic_floating_point_number.sign == '+')
? 0
: (1 << (LITTLENUM_NUMBER_OF_BITS - 1)));
/* Assume 2's complement integers. */
if (exponent_4 <= 0)
{
int prec_bits;
int num_bits;
unget_bits (1);
num_bits = -exponent_4;
prec_bits =
LITTLENUM_NUMBER_OF_BITS * precision - (exponent_bits + 1 + num_bits);
#ifdef TC_I386
if (precision == X_PRECISION && exponent_bits == 15)
{
/* On the i386 a denormalized extended precision float is
shifted down by one, effectively decreasing the exponent
bias by one. */
prec_bits -= 1;
num_bits += 1;
}
#endif
if (num_bits >= LITTLENUM_NUMBER_OF_BITS - exponent_bits)
{
/* Bigger than one littlenum. */
num_bits -= (LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits;
*lp++ = word1;
if (num_bits + exponent_bits + 1
> precision * LITTLENUM_NUMBER_OF_BITS)
{
/* Exponent overflow. */
make_invalid_floating_point_number (words);
return return_value;
}
#ifdef TC_M68K
if (precision == X_PRECISION && exponent_bits == 15)
*lp++ = 0;
#endif
while (num_bits >= LITTLENUM_NUMBER_OF_BITS)
{
num_bits -= LITTLENUM_NUMBER_OF_BITS;
*lp++ = 0;
}
if (num_bits)
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - (num_bits));
}
else
{
if (precision == X_PRECISION && exponent_bits == 15)
{
*lp++ = word1;
#ifdef TC_M68K
*lp++ = 0;
#endif
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - num_bits);
}
else
{
word1 |= next_bits ((LITTLENUM_NUMBER_OF_BITS - 1)
- (exponent_bits + num_bits));
*lp++ = word1;
}
}
while (lp < words_end)
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS);
/* Round the mantissa up, but don't change the number. */
if (next_bits (1))
{
--lp;
if (prec_bits >= LITTLENUM_NUMBER_OF_BITS)
{
int n = 0;
int tmp_bits;
n = 0;
tmp_bits = prec_bits;
while (tmp_bits > LITTLENUM_NUMBER_OF_BITS)
{
if (lp[n] != (LITTLENUM_TYPE) - 1)
break;
--n;
tmp_bits -= LITTLENUM_NUMBER_OF_BITS;
}
if (tmp_bits > LITTLENUM_NUMBER_OF_BITS
|| (lp[n] & mask[tmp_bits]) != mask[tmp_bits]
|| (prec_bits != (precision * LITTLENUM_NUMBER_OF_BITS
- exponent_bits - 1)
#ifdef TC_I386
/* An extended precision float with only the integer
bit set would be invalid. That must be converted
to the smallest normalized number. */
&& !(precision == X_PRECISION
&& prec_bits == (precision * LITTLENUM_NUMBER_OF_BITS
- exponent_bits - 2))
#endif
))
{
unsigned long carry;
for (carry = 1; carry && (lp >= words); lp--)
{
carry = *lp + carry;
*lp = carry;
carry >>= LITTLENUM_NUMBER_OF_BITS;
}
}
else
{
/* This is an overflow of the denormal numbers. We
need to forget what we have produced, and instead
generate the smallest normalized number. */
lp = words;
word1 = ((generic_floating_point_number.sign == '+')
? 0
: (1 << (LITTLENUM_NUMBER_OF_BITS - 1)));
word1 |= (1
<< ((LITTLENUM_NUMBER_OF_BITS - 1)
- exponent_bits));
*lp++ = word1;
#ifdef TC_I386
/* Set the integer bit in the extended precision format.
This cannot happen on the m68k where the mantissa
just overflows into the integer bit above. */
if (precision == X_PRECISION)
*lp++ = 1 << (LITTLENUM_NUMBER_OF_BITS - 1);
#endif
while (lp < words_end)
*lp++ = 0;
}
}
else
*lp += 1;
}
return return_value;
}
else if ((unsigned long) exponent_4 > mask[exponent_bits]
|| (! TC_LARGEST_EXPONENT_IS_NORMAL (precision)
&& (unsigned long) exponent_4 == mask[exponent_bits]))
{
/* Exponent overflow. Lose immediately. */
/* We leave return_value alone: admit we read the
number, but return a floating exception
because we can't encode the number. */
make_invalid_floating_point_number (words);
return return_value;
}
else
{
word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits))
| next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits);
}
*lp++ = word1;
/* X_PRECISION is special: on the 68k, it has 16 bits of zero in the
middle. Either way, it is then followed by a 1 bit. */
if (exponent_bits == 15 && precision == X_PRECISION)
{
#ifdef TC_M68K
*lp++ = 0;
#endif
*lp++ = (1 << (LITTLENUM_NUMBER_OF_BITS - 1)
| next_bits (LITTLENUM_NUMBER_OF_BITS - 1));
}
/* The rest of the words are just mantissa bits. */
while (lp < words_end)
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS);
if (next_bits (1))
{
unsigned long carry;
/* Since the NEXT bit is a 1, round UP the mantissa.
The cunning design of these hidden-1 floats permits
us to let the mantissa overflow into the exponent, and
it 'does the right thing'. However, we lose if the
highest-order bit of the lowest-order word flips.
Is that clear? */
/* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
Please allow at least 1 more bit in carry than is in a LITTLENUM.
We need that extra bit to hold a carry during a LITTLENUM carry
propagation. Another extra bit (kept 0) will assure us that we
don't get a sticky sign bit after shifting right, and that
permits us to propagate the carry without any masking of bits.
#endif */
for (carry = 1, lp--; carry; lp--)
{
carry = *lp + carry;
*lp = carry;
carry >>= LITTLENUM_NUMBER_OF_BITS;
if (lp == words)
break;
}
if (precision == X_PRECISION && exponent_bits == 15)
{
/* Extended precision numbers have an explicit integer bit
that we may have to restore. */
if (lp == words)
{
#ifdef TC_M68K
/* On the m68k there is a gap of 16 bits. We must
explicitly propagate the carry into the exponent. */
words[0] += words[1];
words[1] = 0;
lp++;
#endif
/* Put back the integer bit. */
lp[1] |= 1 << (LITTLENUM_NUMBER_OF_BITS - 1);
}
}
if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)))
{
/* We leave return_value alone: admit we read the number,
but return a floating exception because we can't encode
the number. */
*words &= ~(1 << (LITTLENUM_NUMBER_OF_BITS - 1));
}
}
return return_value;
}
#ifdef TEST
char *
print_gen (gen)
FLONUM_TYPE *gen;
{
FLONUM_TYPE f;
LITTLENUM_TYPE arr[10];
double dv;
float fv;
static char sbuf[40];
if (gen)
{
f = generic_floating_point_number;
generic_floating_point_number = *gen;
}
gen_to_words (&arr[0], 4, 11);
memcpy (&dv, &arr[0], sizeof (double));
sprintf (sbuf, "%x %x %x %x %.14G ", arr[0], arr[1], arr[2], arr[3], dv);
gen_to_words (&arr[0], 2, 8);
memcpy (&fv, &arr[0], sizeof (float));
sprintf (sbuf + strlen (sbuf), "%x %x %.12g\n", arr[0], arr[1], fv);
if (gen)
generic_floating_point_number = f;
return (sbuf);
}
#endif
extern const char FLT_CHARS[];
#define MAX_LITTLENUMS 6
/* This is a utility function called from various tc-*.c files. It
is here in order to reduce code duplication.
Turn a string at input_line_pointer into a floating point constant
of type TYPE (a character found in the FLT_CHARS macro), and store
it as LITTLENUMS in the bytes buffer LITP. The number of chars
emitted is stored in *SIZEP. BIG_WORDIAN is TRUE if the littlenums
should be emitted most significant littlenum first.
An error message is returned, or a NULL pointer if everything went OK. */
char *
ieee_md_atof (int type,
char *litP,
int *sizeP,
bfd_boolean big_wordian)
{
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
int prec = 0;
if (strchr (FLT_CHARS, type) != NULL)
{
switch (type)
{
case 'f':
case 'F':
case 's':
case 'S':
prec = F_PRECISION;
break;
case 'd':
case 'D':
case 'r':
case 'R':
prec = D_PRECISION;
break;
case 't':
case 'T':
prec = X_PRECISION;
type = 'x'; /* This is what atof_ieee() understands. */
break;
case 'x':
case 'X':
case 'p':
case 'P':
#ifdef TC_M68K
/* Note: on the m68k there is a gap of 16 bits (one littlenum)
between the exponent and mantissa. Hence the precision is
6 and not 5. */
prec = P_PRECISION + 1;
#else
prec = P_PRECISION;
#endif
break;
default:
break;
}
}
/* The 'f' and 'd' types are always recognised, even if the target has
not put them into the FLT_CHARS macro. This is because the 'f' type
can come from the .dc.s, .dcb.s, .float or .single pseudo-ops and the
'd' type from the .dc.d, .dbc.d or .double pseudo-ops.
The 'x' type is not implicitly recongised however, even though it can
be generated by the .dc.x and .dbc.x pseudo-ops because not all targets
can support floating point values that big. ie the target has to
explicitly allow them by putting them into FLT_CHARS. */
else if (type == 'f')
prec = F_PRECISION;
else if (type == 'd')
prec = D_PRECISION;
if (prec == 0)
{
*sizeP = 0;
return _("Unrecognized or unsupported floating point constant");
}
gas_assert (prec <= MAX_LITTLENUMS);
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE);
if (big_wordian)
{
for (wordP = words; prec --;)
{
md_number_to_chars (litP, (valueT) (* wordP ++), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
}
else
{
for (wordP = words + prec; prec --;)
{
md_number_to_chars (litP, (valueT) (* -- wordP), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
}
return NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
/* seh pdata/xdata coff object file format
Copyright 2009, 2010, 2012
Free Software Foundation, Inc.
This file is part of GAS.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* Short overview:
There are at the moment three different function entry formats preset.
The first is the MIPS one. The second version
is for ARM, PPC, SH3, and SH4 mainly for Windows CE.
The third is the IA64 and x64 version. Note, the IA64 isn't implemented yet,
but to find information about it, please see specification about IA64 on
http://download.intel.com/design/Itanium/Downloads/245358.pdf file.
The first version has just entries in the pdata section: BeginAddress,
EndAddress, ExceptionHandler, HandlerData, and PrologueEndAddress. Each
value is a pointer to the corresponding data and has size of 4 bytes.
The second variant has the following entries in the pdata section.
BeginAddress, PrologueLength (8 bits), EndAddress (22 bits),
Use-32-bit-instruction (1 bit), and Exception-Handler-Exists (1 bit).
If the FunctionLength is zero, or the Exception-Handler-Exists bit
is true, a PDATA_EH block is placed directly before function entry.
The third version has a function entry block of BeginAddress (RVA),
EndAddress (RVA), and UnwindData (RVA). The description of the
prologue, excepetion-handler, and additional SEH data is stored
within the UNWIND_DATA field in the xdata section.
The pseudos:
.seh_proc <fct_name>
.seh_endprologue
.seh_handler <handler>[,@unwind][,@except] (x64)
.seh_handler <handler>[,<handler_data>] (others)
.seh_handlerdata
.seh_eh
.seh_32/.seh_no32
.seh_endproc
.seh_setframe <reg>,<offset>
.seh_stackalloc
.seh_pushreg
.seh_savereg
.seh_savexmm
.seh_pushframe
*/
/* architecture specific pdata/xdata handling. */
#define SEH_CMDS \
{"seh_proc", obj_coff_seh_proc, 0}, \
{"seh_endproc", obj_coff_seh_endproc, 0}, \
{"seh_pushreg", obj_coff_seh_pushreg, 0}, \
{"seh_savereg", obj_coff_seh_save, 1}, \
{"seh_savexmm", obj_coff_seh_save, 2}, \
{"seh_pushframe", obj_coff_seh_pushframe, 0}, \
{"seh_endprologue", obj_coff_seh_endprologue, 0}, \
{"seh_setframe", obj_coff_seh_setframe, 0}, \
{"seh_stackalloc", obj_coff_seh_stackalloc, 0}, \
{"seh_eh", obj_coff_seh_eh, 0}, \
{"seh_32", obj_coff_seh_32, 1}, \
{"seh_no32", obj_coff_seh_32, 0}, \
{"seh_handler", obj_coff_seh_handler, 0}, \
{"seh_handlerdata", obj_coff_seh_handlerdata, 0},
/* Type definitions. */
typedef struct seh_prologue_element
{
int code;
int info;
offsetT off;
symbolS *pc_addr;
} seh_prologue_element;
typedef struct seh_context
{
struct seh_context *next;
/* Initial code-segment. */
segT code_seg;
/* Function name. */
char *func_name;
/* BeginAddress. */
symbolS *start_addr;
/* EndAddress. */
symbolS *end_addr;
/* Unwind data. */
symbolS *xdata_addr;
/* PrologueEnd. */
symbolS *endprologue_addr;
/* ExceptionHandler. */
expressionS handler;
/* ExceptionHandlerData. (arm, mips) */
expressionS handler_data;
/* ARM .seh_eh directive seen. */
int handler_written;
/* WinCE specific data. */
int use_instruction_32;
/* Was record already processed. */
int done;
/* x64 flags for the xdata header. */
int handler_flags;
int subsection;
/* x64 framereg and frame offset information. */
int framereg;
int frameoff;
/* Information about x64 specific unwind data fields. */
int elems_count;
int elems_max;
seh_prologue_element *elems;
} seh_context;
typedef enum seh_kind {
seh_kind_unknown = 0,
seh_kind_mips = 1, /* Used for MIPS and x86 pdata generation. */
seh_kind_arm = 2, /* Used for ARM, PPC, SH3, and SH4 pdata (PDATA_EH) generation. */
seh_kind_x64 = 3 /* Used for IA64 and x64 pdata/xdata generation. */
} seh_kind;
/* Forward declarations. */
static void obj_coff_seh_stackalloc (int);
static void obj_coff_seh_setframe (int);
static void obj_coff_seh_endprologue (int);
static void obj_coff_seh_save (int);
static void obj_coff_seh_pushreg (int);
static void obj_coff_seh_pushframe (int);
static void obj_coff_seh_endproc (int);
static void obj_coff_seh_eh (int);
static void obj_coff_seh_32 (int);
static void obj_coff_seh_proc (int);
static void obj_coff_seh_handler (int);
static void obj_coff_seh_handlerdata (int);
#define UNDSEC bfd_und_section_ptr
/* Check if x64 UNW_... macros are already defined. */
#ifndef PEX64_FLAG_NHANDLER
/* We can't include here coff/pe.h header. So we have to copy macros
from coff/pe.h here. */
#define PEX64_UNWCODE_CODE(VAL) ((VAL) & 0xf)
#define PEX64_UNWCODE_INFO(VAL) (((VAL) >> 4) & 0xf)
/* The unwind info. */
#define UNW_FLAG_NHANDLER 0
#define UNW_FLAG_EHANDLER 1
#define UNW_FLAG_UHANDLER 2
#define UNW_FLAG_FHANDLER 3
#define UNW_FLAG_CHAININFO 4
#define UNW_FLAG_MASK 0x1f
/* The unwind codes. */
#define UWOP_PUSH_NONVOL 0
#define UWOP_ALLOC_LARGE 1
#define UWOP_ALLOC_SMALL 2
#define UWOP_SET_FPREG 3
#define UWOP_SAVE_NONVOL 4
#define UWOP_SAVE_NONVOL_FAR 5
#define UWOP_SAVE_XMM 6
#define UWOP_SAVE_XMM_FAR 7
#define UWOP_SAVE_XMM128 8
#define UWOP_SAVE_XMM128_FAR 9
#define UWOP_PUSH_MACHFRAME 10
#define PEX64_UWI_VERSION(VAL) ((VAL) & 7)
#define PEX64_UWI_FLAGS(VAL) (((VAL) >> 3) & 0x1f)
#define PEX64_UWI_FRAMEREG(VAL) ((VAL) & 0xf)
#define PEX64_UWI_FRAMEOFF(VAL) (((VAL) >> 4) & 0xf)
#define PEX64_UWI_SIZEOF_UWCODE_ARRAY(VAL) \
((((VAL) + 1) & ~1) * 2)
#define PEX64_OFFSET_TO_UNWIND_CODE 0x4
#define PEX64_OFFSET_TO_HANDLER_RVA (COUNTOFUNWINDCODES) \
(PEX64_OFFSET_TO_UNWIND_CODE + \
PEX64_UWI_SIZEOF_UWCODE_ARRAY(COUNTOFUNWINDCODES))
#define PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) \
(PEX64_OFFSET_TO_HANDLER_RVA(COUNTOFUNWINDCODES) + 4)
#define PEX64_SCOPE_ENTRY(COUNTOFUNWINDCODES, IDX) \
(PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \
PEX64_SCOPE_ENTRY_SIZE * (IDX))
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,415 @@
/* coff object file format
Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
Free Software Foundation, Inc.
This file is part of GAS.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef OBJ_FORMAT_H
#define OBJ_FORMAT_H
#define OBJ_COFF 1
#include "targ-cpu.h"
/* This internal_lineno crap is to stop namespace pollution from the
bfd internal coff headerfile. */
#define internal_lineno bfd_internal_lineno
#include "coff/internal.h"
#undef internal_lineno
/* CPU-specific setup: */
#ifdef TC_ARM
#include "coff/arm.h"
#ifndef TARGET_FORMAT
#define TARGET_FORMAT "coff-arm"
#endif
#endif
#ifdef TC_PPC
#ifdef TE_PE
#include "coff/powerpc.h"
#else
#include "coff/rs6000.h"
#endif
#endif
#ifdef TC_SPARC
#include "coff/sparc.h"
#endif
#ifdef TC_I386
#ifdef TE_PEP
#include "coff/x86_64.h"
#else
#include "coff/i386.h"
#endif
#ifndef TARGET_FORMAT
#ifdef TE_PEP
#define TARGET_FORMAT "coff-x86-64"
#else
#define TARGET_FORMAT "coff-i386"
#endif
#endif
#endif
#ifdef TC_M68K
#include "coff/m68k.h"
#ifndef TARGET_FORMAT
#define TARGET_FORMAT "coff-m68k"
#endif
#endif
#ifdef TC_OR32
#include "coff/or32.h"
#define TARGET_FORMAT "coff-or32-big"
#endif
#ifdef TC_I960
#include "coff/i960.h"
#define TARGET_FORMAT "coff-Intel-little"
#endif
#ifdef TC_Z80
#include "coff/z80.h"
#define TARGET_FORMAT "coff-z80"
#endif
#ifdef TC_Z8K
#include "coff/z8k.h"
#define TARGET_FORMAT "coff-z8k"
#endif
#ifdef TC_H8300
#include "coff/h8300.h"
#define TARGET_FORMAT "coff-h8300"
#endif
#ifdef TC_H8500
#include "coff/h8500.h"
#define TARGET_FORMAT "coff-h8500"
#endif
#ifdef TC_SH
#ifdef TE_PE
#define COFF_WITH_PE
#endif
#include "coff/sh.h"
#ifdef TE_PE
#define TARGET_FORMAT "pe-shl"
#else
#define TARGET_FORMAT \
(!target_big_endian \
? (sh_small ? "coff-shl-small" : "coff-shl") \
: (sh_small ? "coff-sh-small" : "coff-sh"))
#endif
#endif
#ifdef TC_MIPS
#define COFF_WITH_PE
#include "coff/mipspe.h"
#undef TARGET_FORMAT
#define TARGET_FORMAT "pe-mips"
#endif
#ifdef TC_TIC30
#include "coff/tic30.h"
#define TARGET_FORMAT "coff-tic30"
#endif
#ifdef TC_TIC4X
#include "coff/tic4x.h"
#define TARGET_FORMAT "coff2-tic4x"
#endif
#ifdef TC_TIC54X
#include "coff/tic54x.h"
#define TARGET_FORMAT "coff1-c54x"
#endif
#ifdef TC_MCORE
#include "coff/mcore.h"
#ifndef TARGET_FORMAT
#define TARGET_FORMAT "pe-mcore"
#endif
#endif
#ifdef TE_PE
#define obj_set_weak_hook pecoff_obj_set_weak_hook
#define obj_clear_weak_hook pecoff_obj_clear_weak_hook
#endif
#ifndef OBJ_COFF_MAX_AUXENTRIES
#define OBJ_COFF_MAX_AUXENTRIES 1
#endif
#define obj_symbol_new_hook coff_obj_symbol_new_hook
#define obj_symbol_clone_hook coff_obj_symbol_clone_hook
#define obj_read_begin_hook coff_obj_read_begin_hook
#include "bfd/libcoff.h"
#define OUTPUT_FLAVOR bfd_target_coff_flavour
/* Alter the field names, for now, until we've fixed up the other
references to use the new name. */
#ifdef TC_I960
#define TC_SYMFIELD_TYPE symbolS *
#define sy_tc bal
#endif
#define OBJ_SYMFIELD_TYPE unsigned long
#define sy_obj sy_obj_flags
/* We can't use the predefined section symbols in bfd/section.c, as
COFF symbols have extra fields. See bfd/libcoff.h:coff_symbol_type. */
#ifndef obj_sec_sym_ok_for_reloc
#define obj_sec_sym_ok_for_reloc(SEC) ((SEC)->owner != 0)
#endif
#define SYM_AUXENT(S) \
(&coffsymbol (symbol_get_bfdsym (S))->native[1].u.auxent)
#define SYM_AUXINFO(S) \
(&coffsymbol (symbol_get_bfdsym (S))->native[1])
/* The number of auxiliary entries. */
#define S_GET_NUMBER_AUXILIARY(s) \
(coffsymbol (symbol_get_bfdsym (s))->native->u.syment.n_numaux)
/* The number of auxiliary entries. */
#define S_SET_NUMBER_AUXILIARY(s, v) (S_GET_NUMBER_AUXILIARY (s) = (v))
/* True if a symbol name is in the string table, i.e. its length is > 8. */
#define S_IS_STRING(s) (strlen (S_GET_NAME (s)) > 8 ? 1 : 0)
/* Auxiliary entry macros. SA_ stands for symbol auxiliary. */
/* Omit the tv related fields. */
/* Accessors. */
#define SA_GET_SYM_TAGNDX(s) (SYM_AUXENT (s)->x_sym.x_tagndx.l)
#define SA_GET_SYM_LNNO(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno)
#define SA_GET_SYM_SIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size)
#define SA_GET_SYM_FSIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize)
#define SA_GET_SYM_LNNOPTR(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr)
#define SA_GET_SYM_ENDNDX(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_endndx)
#define SA_GET_SYM_DIMEN(s,i) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)])
#define SA_GET_FILE_FNAME(s) (SYM_AUXENT (s)->x_file.x_fname)
#define SA_GET_SCN_SCNLEN(s) (SYM_AUXENT (s)->x_scn.x_scnlen)
#define SA_GET_SCN_NRELOC(s) (SYM_AUXENT (s)->x_scn.x_nreloc)
#define SA_GET_SCN_NLINNO(s) (SYM_AUXENT (s)->x_scn.x_nlinno)
#define SA_SET_SYM_LNNO(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno = (v))
#define SA_SET_SYM_SIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size = (v))
#define SA_SET_SYM_FSIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize = (v))
#define SA_SET_SYM_LNNOPTR(s,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr = (v))
#define SA_SET_SYM_DIMEN(s,i,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)] = (v))
#define SA_SET_FILE_FNAME(s,v) strncpy (SYM_AUXENT (s)->x_file.x_fname, (v), FILNMLEN)
#define SA_SET_SCN_SCNLEN(s,v) (SYM_AUXENT (s)->x_scn.x_scnlen = (v))
#define SA_SET_SCN_NRELOC(s,v) (SYM_AUXENT (s)->x_scn.x_nreloc = (v))
#define SA_SET_SCN_NLINNO(s,v) (SYM_AUXENT (s)->x_scn.x_nlinno = (v))
/* Internal use only definitions. SF_ stands for symbol flags.
These values can be assigned to sy_symbol.ost_flags field of a symbolS.
You'll break i960 if you shift the SYSPROC bits anywhere else. for
more on the balname/callname hack, see tc-i960.h. b.out is done
differently. */
#define SF_I960_MASK 0x000001ff /* Bits 0-8 are used by the i960 port. */
#define SF_SYSPROC 0x0000003f /* bits 0-5 are used to store the sysproc number. */
#define SF_IS_SYSPROC 0x00000040 /* bit 6 marks symbols that are sysprocs. */
#define SF_BALNAME 0x00000080 /* bit 7 marks BALNAME symbols. */
#define SF_CALLNAME 0x00000100 /* bit 8 marks CALLNAME symbols. */
#define SF_NORMAL_MASK 0x0000ffff /* bits 12-15 are general purpose. */
#define SF_STATICS 0x00001000 /* Mark the .text & all symbols. */
#define SF_DEFINED 0x00002000 /* Symbol is defined in this file. */
#define SF_STRING 0x00004000 /* Symbol name length > 8. */
#define SF_LOCAL 0x00008000 /* Symbol must not be emitted. */
#define SF_DEBUG_MASK 0xffff0000 /* bits 16-31 are debug info. */
#define SF_FUNCTION 0x00010000 /* The symbol is a function. */
#define SF_PROCESS 0x00020000 /* Process symbol before write. */
#define SF_TAGGED 0x00040000 /* Is associated with a tag. */
#define SF_TAG 0x00080000 /* Is a tag. */
#define SF_DEBUG 0x00100000 /* Is in debug or abs section. */
#define SF_GET_SEGMENT 0x00200000 /* Get the section of the forward symbol. */
/* All other bits are unused. */
/* Accessors. */
#define SF_GET(s) (* symbol_get_obj (s))
#define SF_GET_DEBUG(s) (symbol_get_bfdsym (s)->flags & BSF_DEBUGGING)
#define SF_SET_DEBUG(s) (symbol_get_bfdsym (s)->flags |= BSF_DEBUGGING)
#define SF_GET_NORMAL_FIELD(s) (SF_GET (s) & SF_NORMAL_MASK)
#define SF_GET_DEBUG_FIELD(s) (SF_GET (s) & SF_DEBUG_MASK)
#define SF_GET_FILE(s) (SF_GET (s) & SF_FILE)
#define SF_GET_STATICS(s) (SF_GET (s) & SF_STATICS)
#define SF_GET_DEFINED(s) (SF_GET (s) & SF_DEFINED)
#define SF_GET_STRING(s) (SF_GET (s) & SF_STRING)
#define SF_GET_LOCAL(s) (SF_GET (s) & SF_LOCAL)
#define SF_GET_FUNCTION(s) (SF_GET (s) & SF_FUNCTION)
#define SF_GET_PROCESS(s) (SF_GET (s) & SF_PROCESS)
#define SF_GET_TAGGED(s) (SF_GET (s) & SF_TAGGED)
#define SF_GET_TAG(s) (SF_GET (s) & SF_TAG)
#define SF_GET_GET_SEGMENT(s) (SF_GET (s) & SF_GET_SEGMENT)
#define SF_GET_I960(s) (SF_GET (s) & SF_I960_MASK) /* Used by i960. */
#define SF_GET_BALNAME(s) (SF_GET (s) & SF_BALNAME) /* Used by i960. */
#define SF_GET_CALLNAME(s) (SF_GET (s) & SF_CALLNAME) /* Used by i960. */
#define SF_GET_IS_SYSPROC(s) (SF_GET (s) & SF_IS_SYSPROC) /* Used by i960. */
#define SF_GET_SYSPROC(s) (SF_GET (s) & SF_SYSPROC) /* Used by i960. */
/* Modifiers. */
#define SF_SET(s,v) (SF_GET (s) = (v))
#define SF_SET_NORMAL_FIELD(s,v)(SF_GET (s) |= ((v) & SF_NORMAL_MASK))
#define SF_SET_DEBUG_FIELD(s,v) (SF_GET (s) |= ((v) & SF_DEBUG_MASK))
#define SF_SET_FILE(s) (SF_GET (s) |= SF_FILE)
#define SF_SET_STATICS(s) (SF_GET (s) |= SF_STATICS)
#define SF_SET_DEFINED(s) (SF_GET (s) |= SF_DEFINED)
#define SF_SET_STRING(s) (SF_GET (s) |= SF_STRING)
#define SF_SET_LOCAL(s) (SF_GET (s) |= SF_LOCAL)
#define SF_CLEAR_LOCAL(s) (SF_GET (s) &= ~SF_LOCAL)
#define SF_SET_FUNCTION(s) (SF_GET (s) |= SF_FUNCTION)
#define SF_SET_PROCESS(s) (SF_GET (s) |= SF_PROCESS)
#define SF_SET_TAGGED(s) (SF_GET (s) |= SF_TAGGED)
#define SF_SET_TAG(s) (SF_GET (s) |= SF_TAG)
#define SF_SET_GET_SEGMENT(s) (SF_GET (s) |= SF_GET_SEGMENT)
#define SF_SET_I960(s,v) (SF_GET (s) |= ((v) & SF_I960_MASK)) /* Used by i960. */
#define SF_SET_BALNAME(s) (SF_GET (s) |= SF_BALNAME) /* Used by i960. */
#define SF_SET_CALLNAME(s) (SF_GET (s) |= SF_CALLNAME) /* Used by i960. */
#define SF_SET_IS_SYSPROC(s) (SF_GET (s) |= SF_IS_SYSPROC) /* Used by i960. */
#define SF_SET_SYSPROC(s,v) (SF_GET (s) |= ((v) & SF_SYSPROC)) /* Used by i960. */
/* Line number handling. */
extern int text_lineno_number;
extern int coff_line_base;
extern int coff_n_line_nos;
extern symbolS *coff_last_function;
#define obj_emit_lineno(WHERE, LINE, FILE_START) abort ()
#define obj_app_file(name, app) c_dot_file_symbol (name, app)
#define obj_frob_symbol(S,P) coff_frob_symbol (S, & P)
#define obj_frob_section(S) coff_frob_section (S)
#define obj_frob_file_after_relocs() coff_frob_file_after_relocs ()
#ifndef obj_adjust_symtab
#define obj_adjust_symtab() coff_adjust_symtab ()
#endif
/* Forward the segment of a forwarded symbol, handle assignments that
just copy symbol values, etc. */
#ifndef OBJ_COPY_SYMBOL_ATTRIBUTES
#ifndef TE_I386AIX
#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest, src) \
(SF_GET_GET_SEGMENT (dest) \
? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \
: 0)
#else
#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest, src) \
(SF_GET_GET_SEGMENT (dest) && S_GET_SEGMENT (dest) == SEG_UNKNOWN \
? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \
: 0)
#endif
#endif
/* Sanity check. */
#ifdef TC_I960
#ifndef C_LEAFSTAT
hey ! Where is the C_LEAFSTAT definition ? i960 - coff support is depending on it.
#endif /* no C_LEAFSTAT */
#endif /* TC_I960 */
extern const pseudo_typeS coff_pseudo_table[];
#ifndef obj_pop_insert
#define obj_pop_insert() pop_insert (coff_pseudo_table)
#endif
/* In COFF, if a symbol is defined using .def/.val SYM/.endef, it's OK
to redefine the symbol later on. This can happen if C symbols use
a prefix, and a symbol is defined both with and without the prefix,
as in start/_start/__start in gcc/libgcc1-test.c. */
#define RESOLVE_SYMBOL_REDEFINITION(sym) \
(SF_GET_GET_SEGMENT (sym) \
? (sym->sy_frag = frag_now, \
S_SET_VALUE (sym, frag_now_fix ()), \
S_SET_SEGMENT (sym, now_seg), \
0) \
: 0)
/* Stabs in a coff file go into their own section. */
#define SEPARATE_STAB_SECTIONS 1
/* We need 12 bytes at the start of the section to hold some initial
information. */
#define INIT_STAB_SECTION(seg) obj_coff_init_stab_section (seg)
/* Store the number of relocations in the section aux entry. */
#define SET_SECTION_RELOCS(sec, relocs, n) \
SA_SET_SCN_NRELOC (section_symbol (sec), n)
#define obj_app_file(name, app) c_dot_file_symbol (name, app)
extern int S_SET_DATA_TYPE (symbolS *, int);
extern int S_SET_STORAGE_CLASS (symbolS *, int);
extern int S_GET_STORAGE_CLASS (symbolS *);
extern void SA_SET_SYM_ENDNDX (symbolS *, symbolS *);
extern void coff_add_linesym (symbolS *);
extern void c_dot_file_symbol (const char *, int);
extern void coff_frob_symbol (symbolS *, int *);
extern void coff_adjust_symtab (void);
extern void coff_frob_section (segT);
extern void coff_adjust_section_syms (bfd *, asection *, void *);
extern void coff_frob_file_after_relocs (void);
extern void coff_obj_symbol_new_hook (symbolS *);
extern void coff_obj_symbol_clone_hook (symbolS *, symbolS *);
extern void coff_obj_read_begin_hook (void);
#ifdef TE_PE
extern void pecoff_obj_set_weak_hook (symbolS *);
extern void pecoff_obj_clear_weak_hook (symbolS *);
#endif
extern void obj_coff_section (int);
extern segT obj_coff_add_segment (const char *);
extern void obj_coff_section (int);
extern void c_dot_file_symbol (const char *, int);
extern segT s_get_segment (symbolS *);
#ifndef tc_coff_symbol_emit_hook
extern void tc_coff_symbol_emit_hook (symbolS *);
#endif
extern void obj_coff_pe_handle_link_once (void);
extern void obj_coff_init_stab_section (segT);
extern void c_section_header (struct internal_scnhdr *,
char *, long, long, long, long,
long, long, long, long);
extern void obj_coff_seh_do_final (void);
#ifndef obj_coff_generate_pdata
#define obj_coff_generate_pdata obj_coff_seh_do_final
#endif
#endif /* OBJ_FORMAT_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,342 @@
/* tc-i386.h -- Header file for tc-i386.c
Copyright 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef TC_I386
#define TC_I386 1
#include "opcodes/i386-opc.h"
struct fix;
#define TARGET_BYTES_BIG_ENDIAN 0
#define TARGET_ARCH (i386_arch ())
#define TARGET_MACH (i386_mach ())
extern enum bfd_architecture i386_arch (void);
extern unsigned long i386_mach (void);
#ifdef TE_FreeBSD
#define AOUT_TARGET_FORMAT "a.out-i386-freebsd"
#endif
#ifdef TE_NetBSD
#define AOUT_TARGET_FORMAT "a.out-i386-netbsd"
#endif
#ifdef TE_386BSD
#define AOUT_TARGET_FORMAT "a.out-i386-bsd"
#endif
#ifdef TE_LINUX
#define AOUT_TARGET_FORMAT "a.out-i386-linux"
#endif
#ifdef TE_Mach
#define AOUT_TARGET_FORMAT "a.out-mach3"
#endif
#ifdef TE_DYNIX
#define AOUT_TARGET_FORMAT "a.out-i386-dynix"
#endif
#ifndef AOUT_TARGET_FORMAT
#define AOUT_TARGET_FORMAT "a.out-i386"
#endif
#ifdef TE_FreeBSD
#define ELF_TARGET_FORMAT "elf32-i386-freebsd"
#define ELF_TARGET_FORMAT64 "elf64-x86-64-freebsd"
#elif defined (TE_VXWORKS)
#define ELF_TARGET_FORMAT "elf32-i386-vxworks"
#elif defined (TE_NACL)
#define ELF_TARGET_FORMAT "elf32-i386-nacl"
#define ELF_TARGET_FORMAT32 "elf32-x86-64-nacl"
#define ELF_TARGET_FORMAT64 "elf64-x86-64-nacl"
#endif
#ifdef TE_SOLARIS
#define ELF_TARGET_FORMAT "elf32-i386-sol2"
#define ELF_TARGET_FORMAT64 "elf64-x86-64-sol2"
#endif
#ifndef ELF_TARGET_FORMAT
#define ELF_TARGET_FORMAT "elf32-i386"
#endif
#ifndef ELF_TARGET_FORMAT64
#define ELF_TARGET_FORMAT64 "elf64-x86-64"
#endif
#ifndef ELF_TARGET_FORMAT32
#define ELF_TARGET_FORMAT32 "elf32-x86-64"
#endif
#ifndef ELF_TARGET_L1OM_FORMAT
#define ELF_TARGET_L1OM_FORMAT "elf64-l1om"
#endif
#ifndef ELF_TARGET_K1OM_FORMAT
#define ELF_TARGET_K1OM_FORMAT "elf64-k1om"
#endif
#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
|| defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
extern const char *i386_target_format (void);
#define TARGET_FORMAT i386_target_format ()
#else
#ifdef TE_GO32
#define TARGET_FORMAT "coff-go32"
#endif
#ifdef OBJ_AOUT
#define TARGET_FORMAT AOUT_TARGET_FORMAT
#endif
#endif
#if (defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF))
#define md_end i386_elf_emit_arch_note
extern void i386_elf_emit_arch_note (void);
#endif
#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0
/* '$' may be used as immediate prefix. */
#undef LOCAL_LABELS_DOLLAR
#define LOCAL_LABELS_DOLLAR 0
#undef LOCAL_LABELS_FB
#define LOCAL_LABELS_FB 1
extern const char extra_symbol_chars[];
#define tc_symbol_chars extra_symbol_chars
extern const char *i386_comment_chars;
#define tc_comment_chars i386_comment_chars
/* The name of the global offset table generated by the compiler. Allow
this to be overridden if need be. */
#ifndef GLOBAL_OFFSET_TABLE_NAME
#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
#endif
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && !defined (LEX_AT)
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES)
#endif
extern void x86_cons (expressionS *, int);
#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) x86_cons_fix_new(FRAG, OFF, LEN, EXP)
extern void x86_cons_fix_new
(fragS *, unsigned int, unsigned int, expressionS *);
#define TC_ADDRESS_BYTES x86_address_bytes
extern int x86_address_bytes (void);
#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */
#define NO_RELOC BFD_RELOC_NONE
void i386_validate_fix (struct fix *);
#define TC_VALIDATE_FIX(FIX,SEGTYPE,SKIP) i386_validate_fix(FIX)
#define tc_fix_adjustable(X) tc_i386_fix_adjustable(X)
extern int tc_i386_fix_adjustable (struct fix *);
/* Values passed to md_apply_fix don't include the symbol value. */
#define MD_APPLY_SYM_VALUE(FIX) 0
/* ELF wants external syms kept, as does PE COFF. */
#if defined (TE_PE) && defined (STRICT_PE_FORMAT)
#define EXTERN_FORCE_RELOC \
(OUTPUT_FLAVOR == bfd_target_elf_flavour \
|| OUTPUT_FLAVOR == bfd_target_coff_flavour)
#else
#define EXTERN_FORCE_RELOC \
(OUTPUT_FLAVOR == bfd_target_elf_flavour)
#endif
/* This expression evaluates to true if the relocation is for a local
object for which we still want to do the relocation at runtime.
False if we are willing to perform this relocation while building
the .o file. GOTOFF and GOT32 do not need to be checked here because
they are not pcrel. .*/
#define TC_FORCE_RELOCATION_LOCAL(FIX) \
(!(FIX)->fx_pcrel \
|| (FIX)->fx_r_type == BFD_RELOC_386_PLT32 \
|| (FIX)->fx_r_type == BFD_RELOC_386_GOTPC \
|| (FIX)->fx_r_type == BFD_RELOC_X86_64_GOTPCREL \
|| TC_FORCE_RELOCATION (FIX))
extern int i386_parse_name (char *, expressionS *, char *);
#define md_parse_name(s, e, m, c) i386_parse_name (s, e, c)
extern operatorT i386_operator (const char *name, unsigned int operands, char *);
#define md_operator i386_operator
extern int i386_need_index_operator (void);
#define md_need_index_operator i386_need_index_operator
#define md_register_arithmetic 0
extern const struct relax_type md_relax_table[];
#define TC_GENERIC_RELAX_TABLE md_relax_table
extern int optimize_align_code;
#define md_do_align(n, fill, len, max, around) \
if ((n) \
&& !need_pass_2 \
&& optimize_align_code \
&& (!(fill) \
|| ((char)*(fill) == (char)0x90 && (len) == 1)) \
&& subseg_text_p (now_seg)) \
{ \
frag_align_code ((n), (max)); \
goto around; \
}
#define MAX_MEM_FOR_RS_ALIGN_CODE 31
extern void i386_align_code (fragS *, int);
#define HANDLE_ALIGN(fragP) \
if (fragP->fr_type == rs_align_code) \
i386_align_code (fragP, (fragP->fr_next->fr_address \
- fragP->fr_address \
- fragP->fr_fix));
void i386_print_statistics (FILE *);
#define tc_print_statistics i386_print_statistics
extern unsigned int i386_frag_max_var (fragS *);
#define md_frag_max_var i386_frag_max_var
#define md_number_to_chars number_to_chars_littleendian
enum processor_type
{
PROCESSOR_UNKNOWN,
PROCESSOR_I386,
PROCESSOR_I486,
PROCESSOR_PENTIUM,
PROCESSOR_PENTIUMPRO,
PROCESSOR_PENTIUM4,
PROCESSOR_NOCONA,
PROCESSOR_CORE,
PROCESSOR_CORE2,
PROCESSOR_COREI7,
PROCESSOR_L1OM,
PROCESSOR_K1OM,
PROCESSOR_K6,
PROCESSOR_ATHLON,
PROCESSOR_K8,
PROCESSOR_GENERIC32,
PROCESSOR_GENERIC64,
PROCESSOR_AMDFAM10,
PROCESSOR_BD,
PROCESSOR_BT
};
extern enum processor_type cpu_arch_tune;
extern enum processor_type cpu_arch_isa;
extern i386_cpu_flags cpu_arch_isa_flags;
struct i386_tc_frag_data
{
enum processor_type isa;
i386_cpu_flags isa_flags;
enum processor_type tune;
};
/* We need to emit the right NOP pattern in .align frags. This is
done after the text-to-bits assembly pass, so we need to mark it with
the isa/tune settings at the time the .align was assembled. */
#define TC_FRAG_TYPE struct i386_tc_frag_data
#define TC_FRAG_INIT(FRAGP) \
do \
{ \
(FRAGP)->tc_frag_data.isa = cpu_arch_isa; \
(FRAGP)->tc_frag_data.isa_flags = cpu_arch_isa_flags; \
(FRAGP)->tc_frag_data.tune = cpu_arch_tune; \
} \
while (0)
#ifdef SCO_ELF
#define tc_init_after_args() sco_id ()
extern void sco_id (void);
#endif
#define WORKING_DOT_WORD 1
/* We want .cfi_* pseudo-ops for generating unwind info. */
#define TARGET_USE_CFIPOP 1
extern unsigned int x86_dwarf2_return_column;
#define DWARF2_DEFAULT_RETURN_COLUMN x86_dwarf2_return_column
extern int x86_cie_data_alignment;
#define DWARF2_CIE_DATA_ALIGNMENT x86_cie_data_alignment
extern int x86_dwarf2_addr_size (void);
#define DWARF2_ADDR_SIZE(bfd) x86_dwarf2_addr_size ()
#define tc_parse_to_dw2regnum tc_x86_parse_to_dw2regnum
extern void tc_x86_parse_to_dw2regnum (expressionS *);
#define tc_cfi_frame_initial_instructions tc_x86_frame_initial_instructions
extern void tc_x86_frame_initial_instructions (void);
#define md_elf_section_type(str,len) i386_elf_section_type (str, len)
extern int i386_elf_section_type (const char *, size_t);
#ifdef TE_SOLARIS
#define md_fix_up_eh_frame(sec) i386_solaris_fix_up_eh_frame (sec)
extern void i386_solaris_fix_up_eh_frame (segT);
#endif
/* Support for SHF_X86_64_LARGE */
extern bfd_vma x86_64_section_word (char *, size_t);
extern bfd_vma x86_64_section_letter (int, char **);
#define md_elf_section_letter(LETTER, PTR_MSG) x86_64_section_letter (LETTER, PTR_MSG)
#define md_elf_section_word(STR, LEN) x86_64_section_word (STR, LEN)
#ifdef TE_PE
#define O_secrel O_md1
#define TC_DWARF2_EMIT_OFFSET tc_pe_dwarf2_emit_offset
void tc_pe_dwarf2_emit_offset (symbolS *, unsigned int);
#endif /* TE_PE */
/* X_add_symbol:X_op_symbol (Intel mode only) */
#define O_full_ptr O_md2
#ifdef OBJ_MACH_O
#define TC_FORCE_RELOCATION(FIX) (obj_mach_o_force_reloc (FIX))
#define TC_FORCE_RELOCATION_SUB_SAME(FIX,SEG) \
(obj_mach_o_force_reloc_sub_same (FIX, SEG))
#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX,SEG) \
(obj_mach_o_force_reloc_sub_local (FIX, SEG))
#define TC_VALIDATE_FIX_SUB(FIX, SEG) 1
#endif /* OBJ_MACH_O */
#endif /* TC_I386 */

View File

@ -0,0 +1,26 @@
/* Copyright 2007 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3,
or (at your option) any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#define TE_PE
#define LEX_AT (LEX_BEGIN_NAME | LEX_NAME) /* Can have @'s inside labels. */
/* The PE format supports long section names. */
#define COFF_LONG_SECTION_NAMES
#include "obj-format.h"

View File

@ -0,0 +1,208 @@
/* depend.c - Handle dependency tracking.
Copyright 1997, 1998, 2000, 2001, 2003, 2004, 2005, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "filenames.h"
/* The file to write to, or NULL if no dependencies being kept. */
static char * dep_file = NULL;
struct dependency
{
char * file;
struct dependency * next;
};
/* All the files we depend on. */
static struct dependency * dep_chain = NULL;
/* Current column in output file. */
static int column = 0;
static int quote_string_for_make (FILE *, char *);
static void wrap_output (FILE *, char *, int);
/* Number of columns allowable. */
#define MAX_COLUMNS 72
/* Start saving dependencies, to be written to FILENAME. If this is
never called, then dependency tracking is simply skipped. */
void
start_dependencies (char *filename)
{
dep_file = filename;
}
/* Noticed a new filename, so try to register it. */
void
register_dependency (char *filename)
{
struct dependency *dep;
if (dep_file == NULL)
return;
for (dep = dep_chain; dep != NULL; dep = dep->next)
{
if (!filename_cmp (filename, dep->file))
return;
}
dep = (struct dependency *) xmalloc (sizeof (struct dependency));
dep->file = xstrdup (filename);
dep->next = dep_chain;
dep_chain = dep;
}
/* Quote a file name the way `make' wants it, and print it to FILE.
If FILE is NULL, do no printing, but return the length of the
quoted string.
This code is taken from gcc with only minor changes. */
static int
quote_string_for_make (FILE *file, char *src)
{
char *p = src;
int i = 0;
for (;;)
{
char c = *p++;
switch (c)
{
case '\0':
case ' ':
case '\t':
{
/* GNU make uses a weird quoting scheme for white space.
A space or tab preceded by 2N+1 backslashes represents
N backslashes followed by space; a space or tab
preceded by 2N backslashes represents N backslashes at
the end of a file name; and backslashes in other
contexts should not be doubled. */
char *q;
for (q = p - 1; src < q && q[-1] == '\\'; q--)
{
if (file)
putc ('\\', file);
i++;
}
}
if (!c)
return i;
if (file)
putc ('\\', file);
i++;
goto ordinary_char;
case '$':
if (file)
putc (c, file);
i++;
/* Fall through. This can mishandle things like "$(" but
there's no easy fix. */
default:
ordinary_char:
/* This can mishandle characters in the string "\0\n%*?[\\~";
exactly which chars are mishandled depends on the `make' version.
We know of no portable solution for this;
even GNU make 3.76.1 doesn't solve the problem entirely.
(Also, '\0' is mishandled due to our calling conventions.) */
if (file)
putc (c, file);
i++;
break;
}
}
}
/* Append some output to the file, keeping track of columns and doing
wrapping as necessary. */
static void
wrap_output (FILE *f, char *string, int spacer)
{
int len = quote_string_for_make (NULL, string);
if (len == 0)
return;
if (column
&& (MAX_COLUMNS
- 1 /* spacer */
- 2 /* ` \' */
< column + len))
{
fprintf (f, " \\\n ");
column = 0;
if (spacer == ' ')
spacer = '\0';
}
if (spacer == ' ')
{
putc (spacer, f);
++column;
}
quote_string_for_make (f, string);
column += len;
if (spacer == ':')
{
putc (spacer, f);
++column;
}
}
/* Print dependency file. */
void
print_dependencies (void)
{
FILE *f;
struct dependency *dep;
if (dep_file == NULL)
return;
f = fopen (dep_file, FOPEN_WT);
if (f == NULL)
{
as_warn (_("can't open `%s' for writing"), dep_file);
return;
}
column = 0;
wrap_output (f, out_file_name, ':');
for (dep = dep_chain; dep != NULL; dep = dep->next)
wrap_output (f, dep->file, ' ');
putc ('\n', f);
if (fclose (f))
as_warn (_("can't close `%s'"), dep_file);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
/* dw2gencfi.h - Support for generating Dwarf2 CFI information.
Copyright 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
Contributed by Michal Ludvig <mludvig@suse.cz>
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef DW2GENCFI_H
#define DW2GENCFI_H
#include "dwarf2.h"
struct symbol;
extern const pseudo_typeS cfi_pseudo_table[];
/* cfi_finish() is called at the end of file. It will complain if
the last CFI wasn't properly closed by .cfi_endproc. */
extern void cfi_finish (void);
/* Entry points for backends to add unwind information. */
extern void cfi_new_fde (struct symbol *);
extern void cfi_end_fde (struct symbol *);
extern void cfi_set_return_column (unsigned);
extern void cfi_add_advance_loc (struct symbol *);
extern void cfi_add_CFA_offset (unsigned, offsetT);
extern void cfi_add_CFA_def_cfa (unsigned, offsetT);
extern void cfi_add_CFA_register (unsigned, unsigned);
extern void cfi_add_CFA_def_cfa_register (unsigned);
extern void cfi_add_CFA_def_cfa_offset (offsetT);
extern void cfi_add_CFA_restore (unsigned);
extern void cfi_add_CFA_undefined (unsigned);
extern void cfi_add_CFA_same_value (unsigned);
extern void cfi_add_CFA_remember_state (void);
extern void cfi_add_CFA_restore_state (void);
/* Structures for md_cfi_end. */
#if defined (TE_PE) || defined (TE_PEP)
#define SUPPORT_FRAME_LINKONCE 1
#else
#define SUPPORT_FRAME_LINKONCE 0
#endif
struct cfi_insn_data
{
struct cfi_insn_data *next;
#if SUPPORT_FRAME_LINKONCE
segT cur_seg;
#endif
int insn;
union
{
struct
{
unsigned reg;
offsetT offset;
} ri;
struct
{
unsigned reg1;
unsigned reg2;
} rr;
unsigned r;
offsetT i;
struct
{
symbolS *lab1;
symbolS *lab2;
} ll;
struct cfi_escape_data *esc;
struct
{
unsigned reg, encoding;
expressionS exp;
} ea;
} u;
};
struct fde_entry
{
struct fde_entry *next;
#if SUPPORT_FRAME_LINKONCE
segT cur_seg;
#endif
symbolS *start_address;
symbolS *end_address;
struct cfi_insn_data *data;
struct cfi_insn_data **last;
unsigned char per_encoding;
unsigned char lsda_encoding;
expressionS personality;
expressionS lsda;
unsigned int return_column;
unsigned int signal_frame;
#if SUPPORT_FRAME_LINKONCE
int handled;
#endif
};
/* The list of all FDEs that have been collected. */
extern struct fde_entry *all_fde_data;
/* Fake CFI type; outside the byte range of any real CFI insn. */
#define CFI_adjust_cfa_offset 0x100
#define CFI_return_column 0x101
#define CFI_rel_offset 0x102
#define CFI_escape 0x103
#define CFI_signal_frame 0x104
#define CFI_val_encoded_addr 0x105
#endif /* DW2GENCFI_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
/* dwarf2dbg.h - DWARF2 debug support
Copyright 1999, 2000, 2002, 2003, 2005, 2006, 2007, 2009
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef AS_DWARF2DBG_H
#define AS_DWARF2DBG_H
#include "as.h"
#define DWARF2_FLAG_IS_STMT (1 << 0)
#define DWARF2_FLAG_BASIC_BLOCK (1 << 1)
#define DWARF2_FLAG_PROLOGUE_END (1 << 2)
#define DWARF2_FLAG_EPILOGUE_BEGIN (1 << 3)
struct dwarf2_line_info {
unsigned int filenum;
unsigned int line;
unsigned int column;
unsigned int isa;
unsigned int flags;
unsigned int discriminator;
};
/* Implements the .file FILENO "FILENAME" directive. FILENO can be 0
to indicate that no file number has been assigned. All real file
number must be >0. */
extern char *dwarf2_directive_file (int dummy);
/* Implements the .loc FILENO LINENO [COLUMN] directive. FILENO is
the file number, LINENO the line number and the (optional) COLUMN
the column of the source code that the following instruction
corresponds to. FILENO can be 0 to indicate that the filename
specified by the textually most recent .file directive should be
used. */
extern void dwarf2_directive_loc (int dummy);
/* Implements the .loc_mark_labels {0,1} directive. */
extern void dwarf2_directive_loc_mark_labels (int dummy);
/* Returns the current source information. If .file directives have
been encountered, the info for the corresponding source file is
returned. Otherwise, the info for the assembly source file is
returned. */
extern void dwarf2_where (struct dwarf2_line_info *l);
/* A hook to allow the target backend to inform the line number state
machine of isa changes when assembler debug info is enabled. */
extern void dwarf2_set_isa (unsigned int isa);
/* This function generates .debug_line info based on the address and
source information passed in the arguments. ADDR should be the
frag-relative offset of the instruction the information is for and
L is the source information that should be associated with that
address. */
extern void dwarf2_gen_line_info (addressT addr, struct dwarf2_line_info *l);
/* Must be called for each generated instruction. */
extern void dwarf2_emit_insn (int);
void dwarf2_move_insn (int);
/* Reset the state of the line number information to reflect that
it has been used. */
extern void dwarf2_consume_line_info (void);
/* Should be called for each code label. */
extern void dwarf2_emit_label (symbolS *);
/* True when we've seen a .loc directive recently. Used to avoid
doing work when there's nothing to do. */
extern bfd_boolean dwarf2_loc_directive_seen;
/* True when we're supposed to set the basic block mark whenever a label
is seen. Unless the target is doing Something Weird, just call
dwarf2_emit_label. */
extern bfd_boolean dwarf2_loc_mark_labels;
extern void dwarf2_init (void);
extern void dwarf2_finish (void);
extern int dwarf2dbg_estimate_size_before_relax (fragS *);
extern int dwarf2dbg_relax_frag (fragS *);
extern void dwarf2dbg_convert_frag (fragS *);
/* An enumeration which describes the sizes of offsets (to DWARF sections)
and the mechanism by which the size is indicated. */
enum dwarf2_format {
/* 32-bit format: the initial length field is 4 bytes long. */
dwarf2_format_32bit,
/* DWARF3 64-bit format: the representation of the initial length
(of a DWARF section) is 0xffffffff (4 bytes) followed by eight
bytes indicating the actual length. */
dwarf2_format_64bit,
/* SGI extension to DWARF2: The initial length is eight bytes. */
dwarf2_format_64bit_irix
};
#endif /* AS_DWARF2DBG_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,113 @@
/* ecoff.h -- header file for ECOFF debugging support
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2003, 2004, 2005,
2007, 2009 Free Software Foundation, Inc.
Contributed by Cygnus Support.
Put together by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef GAS_ECOFF_H
#define GAS_ECOFF_H
#ifdef ECOFF_DEBUGGING
#include "coff/sym.h"
#include "coff/ecoff.h"
/* Whether we have seen any ECOFF debugging information. */
extern int ecoff_debugging_seen;
/* This function should be called at the start of assembly, by
obj_read_begin_hook. */
extern void ecoff_read_begin_hook (void);
/* This function should be called when the assembler switches to a new
file. */
extern void ecoff_new_file (const char *, int);
/* This function should be called when a new symbol is created, by
obj_symbol_new_hook. */
extern void ecoff_symbol_new_hook (symbolS *);
extern void ecoff_symbol_clone_hook (symbolS *, symbolS *);
/* This function should be called by the obj_frob_symbol hook. */
extern void ecoff_frob_symbol (symbolS *);
/* Build the ECOFF debugging information. This should be called by
obj_frob_file. This fills in the counts in *HDR; the offsets are
filled in relative to the start of the *BUFP. It sets *BUFP to a
block of memory holding the debugging information. It returns the
length of *BUFP. */
extern unsigned long ecoff_build_debug
(HDRR *hdr, char **bufp, const struct ecoff_debug_swap *);
/* Functions to handle the ECOFF debugging directives. */
extern void ecoff_directive_begin (int);
extern void ecoff_directive_bend (int);
extern void ecoff_directive_end (int);
extern void ecoff_directive_ent (int);
extern void ecoff_directive_fmask (int);
extern void ecoff_directive_frame (int);
extern void ecoff_directive_loc (int);
extern void ecoff_directive_mask (int);
/* Other ECOFF directives. */
extern void ecoff_directive_extern (int);
extern void ecoff_directive_weakext (int);
/* Functions to handle the COFF debugging directives. */
extern void ecoff_directive_def (int);
extern void ecoff_directive_dim (int);
extern void ecoff_directive_endef (int);
extern void ecoff_directive_file (int);
extern void ecoff_directive_scl (int);
extern void ecoff_directive_size (int);
extern void ecoff_directive_tag (int);
extern void ecoff_directive_type (int);
extern void ecoff_directive_val (int);
/* Handle stabs. */
extern void ecoff_stab (segT sec, int what, const char *string,
int type, int other, int desc);
/* Set the GP prologue size. */
extern void ecoff_set_gp_prolog_size (int sz);
/* This routine is called from the ECOFF code to set the external
information for a symbol. */
#ifndef obj_ecoff_set_ext
extern void obj_ecoff_set_ext (symbolS *, EXTR *);
#endif
/* This routine is used to patch up a line number directive when
instructions are moved around. */
extern void ecoff_fix_loc (fragS *, unsigned long);
/* This function is called from read.c to peek at cur_file_ptr. */
extern int ecoff_no_current_file (void);
/* This function returns the symbol associated with the current proc. */
extern symbolS *ecoff_get_cur_proc_sym (void);
#endif /* ECOFF_DEBUGGING */
/* This routine is called from read.c to generate line number for .s file. */
extern void ecoff_generate_asm_lineno (void);
#endif /* ! GAS_ECOFF_H */

View File

@ -0,0 +1,557 @@
/* ehopt.c--optimize gcc exception frame information.
Copyright 1998, 2000, 2001, 2003, 2005, 2007, 2008, 2009
Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "subsegs.h"
#include "struc-symbol.h"
/* We include this ELF file, even though we may not be assembling for
ELF, since the exception frame information is always in a format
derived from DWARF. */
#include "dwarf2.h"
/* Try to optimize gcc 2.8 exception frame information.
Exception frame information is emitted for every function in the
.eh_frame or .debug_frame sections. Simple information for a function
with no exceptions looks like this:
__FRAME_BEGIN__:
.4byte .LLCIE1 / Length of Common Information Entry
.LSCIE1:
#if .eh_frame
.4byte 0x0 / CIE Identifier Tag
#elif .debug_frame
.4byte 0xffffffff / CIE Identifier Tag
#endif
.byte 0x1 / CIE Version
.byte 0x0 / CIE Augmentation (none)
.byte 0x1 / ULEB128 0x1 (CIE Code Alignment Factor)
.byte 0x7c / SLEB128 -4 (CIE Data Alignment Factor)
.byte 0x8 / CIE RA Column
.byte 0xc / DW_CFA_def_cfa
.byte 0x4 / ULEB128 0x4
.byte 0x4 / ULEB128 0x4
.byte 0x88 / DW_CFA_offset, column 0x8
.byte 0x1 / ULEB128 0x1
.align 4
.LECIE1:
.set .LLCIE1,.LECIE1-.LSCIE1 / CIE Length Symbol
.4byte .LLFDE1 / FDE Length
.LSFDE1:
.4byte .LSFDE1-__FRAME_BEGIN__ / FDE CIE offset
.4byte .LFB1 / FDE initial location
.4byte .LFE1-.LFB1 / FDE address range
.byte 0x4 / DW_CFA_advance_loc4
.4byte .LCFI0-.LFB1
.byte 0xe / DW_CFA_def_cfa_offset
.byte 0x8 / ULEB128 0x8
.byte 0x85 / DW_CFA_offset, column 0x5
.byte 0x2 / ULEB128 0x2
.byte 0x4 / DW_CFA_advance_loc4
.4byte .LCFI1-.LCFI0
.byte 0xd / DW_CFA_def_cfa_register
.byte 0x5 / ULEB128 0x5
.byte 0x4 / DW_CFA_advance_loc4
.4byte .LCFI2-.LCFI1
.byte 0x2e / DW_CFA_GNU_args_size
.byte 0x4 / ULEB128 0x4
.byte 0x4 / DW_CFA_advance_loc4
.4byte .LCFI3-.LCFI2
.byte 0x2e / DW_CFA_GNU_args_size
.byte 0x0 / ULEB128 0x0
.align 4
.LEFDE1:
.set .LLFDE1,.LEFDE1-.LSFDE1 / FDE Length Symbol
The immediate issue we can address in the assembler is the
DW_CFA_advance_loc4 followed by a four byte value. The value is
the difference of two addresses in the function. Since gcc does
not know this value, it always uses four bytes. We will know the
value at the end of assembly, so we can do better. */
struct cie_info
{
unsigned code_alignment;
int z_augmentation;
};
static int get_cie_info (struct cie_info *);
/* Extract information from the CIE. */
static int
get_cie_info (struct cie_info *info)
{
fragS *f;
fixS *fix;
int offset;
char CIE_id;
char augmentation[10];
int iaug;
int code_alignment = 0;
/* We should find the CIE at the start of the section. */
f = seg_info (now_seg)->frchainP->frch_root;
fix = seg_info (now_seg)->frchainP->fix_root;
/* Look through the frags of the section to find the code alignment. */
/* First make sure that the CIE Identifier Tag is 0/-1. */
if (strncmp (segment_name (now_seg), ".debug_frame", 12) == 0)
CIE_id = (char)0xff;
else
CIE_id = 0;
offset = 4;
while (f != NULL && offset >= f->fr_fix)
{
offset -= f->fr_fix;
f = f->fr_next;
}
if (f == NULL
|| f->fr_fix - offset < 4
|| f->fr_literal[offset] != CIE_id
|| f->fr_literal[offset + 1] != CIE_id
|| f->fr_literal[offset + 2] != CIE_id
|| f->fr_literal[offset + 3] != CIE_id)
return 0;
/* Next make sure the CIE version number is 1. */
offset += 4;
while (f != NULL && offset >= f->fr_fix)
{
offset -= f->fr_fix;
f = f->fr_next;
}
if (f == NULL
|| f->fr_fix - offset < 1
|| f->fr_literal[offset] != 1)
return 0;
/* Skip the augmentation (a null terminated string). */
iaug = 0;
++offset;
while (1)
{
while (f != NULL && offset >= f->fr_fix)
{
offset -= f->fr_fix;
f = f->fr_next;
}
if (f == NULL)
return 0;
while (offset < f->fr_fix && f->fr_literal[offset] != '\0')
{
if ((size_t) iaug < (sizeof augmentation) - 1)
{
augmentation[iaug] = f->fr_literal[offset];
++iaug;
}
++offset;
}
if (offset < f->fr_fix)
break;
}
++offset;
while (f != NULL && offset >= f->fr_fix)
{
offset -= f->fr_fix;
f = f->fr_next;
}
if (f == NULL)
return 0;
augmentation[iaug] = '\0';
if (augmentation[0] == '\0')
{
/* No augmentation. */
}
else if (strcmp (augmentation, "eh") == 0)
{
/* We have to skip a pointer. Unfortunately, we don't know how
large it is. We find out by looking for a matching fixup. */
while (fix != NULL
&& (fix->fx_frag != f || fix->fx_where != offset))
fix = fix->fx_next;
if (fix == NULL)
offset += 4;
else
offset += fix->fx_size;
while (f != NULL && offset >= f->fr_fix)
{
offset -= f->fr_fix;
f = f->fr_next;
}
if (f == NULL)
return 0;
}
else if (augmentation[0] != 'z')
return 0;
/* We're now at the code alignment factor, which is a ULEB128. If
it isn't a single byte, forget it. */
code_alignment = f->fr_literal[offset] & 0xff;
if ((code_alignment & 0x80) != 0)
code_alignment = 0;
info->code_alignment = code_alignment;
info->z_augmentation = (augmentation[0] == 'z');
return 1;
}
enum frame_state
{
state_idle,
state_saw_size,
state_saw_cie_offset,
state_saw_pc_begin,
state_seeing_aug_size,
state_skipping_aug,
state_wait_loc4,
state_saw_loc4,
state_error,
};
/* This function is called from emit_expr. It looks for cases which
we can optimize.
Rather than try to parse all this information as we read it, we
look for a single byte DW_CFA_advance_loc4 followed by a 4 byte
difference. We turn that into a rs_cfa_advance frag, and handle
those frags at the end of the assembly. If the gcc output changes
somewhat, this optimization may stop working.
This function returns non-zero if it handled the expression and
emit_expr should not do anything, or zero otherwise. It can also
change *EXP and *PNBYTES. */
int
check_eh_frame (expressionS *exp, unsigned int *pnbytes)
{
struct frame_data
{
enum frame_state state;
int cie_info_ok;
struct cie_info cie_info;
symbolS *size_end_sym;
fragS *loc4_frag;
int loc4_fix;
int aug_size;
int aug_shift;
};
static struct frame_data eh_frame_data;
static struct frame_data debug_frame_data;
struct frame_data *d;
/* Don't optimize. */
if (flag_traditional_format)
return 0;
#ifdef md_allow_eh_opt
if (! md_allow_eh_opt)
return 0;
#endif
/* Select the proper section data. */
if (strncmp (segment_name (now_seg), ".eh_frame", 9) == 0
&& segment_name (now_seg)[9] != '_')
d = &eh_frame_data;
else if (strncmp (segment_name (now_seg), ".debug_frame", 12) == 0)
d = &debug_frame_data;
else
return 0;
if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym))
{
/* We have come to the end of the CIE or FDE. See below where
we set saw_size. We must check this first because we may now
be looking at the next size. */
d->state = state_idle;
}
switch (d->state)
{
case state_idle:
if (*pnbytes == 4)
{
/* This might be the size of the CIE or FDE. We want to know
the size so that we don't accidentally optimize across an FDE
boundary. We recognize the size in one of two forms: a
symbol which will later be defined as a difference, or a
subtraction of two symbols. Either way, we can tell when we
are at the end of the FDE because the symbol becomes defined
(in the case of a subtraction, the end symbol, from which the
start symbol is being subtracted). Other ways of describing
the size will not be optimized. */
if ((exp->X_op == O_symbol || exp->X_op == O_subtract)
&& ! S_IS_DEFINED (exp->X_add_symbol))
{
d->state = state_saw_size;
d->size_end_sym = exp->X_add_symbol;
}
}
break;
case state_saw_size:
case state_saw_cie_offset:
/* Assume whatever form it appears in, it appears atomically. */
d->state = (enum frame_state) (d->state + 1);
break;
case state_saw_pc_begin:
/* Decide whether we should see an augmentation. */
if (! d->cie_info_ok
&& ! (d->cie_info_ok = get_cie_info (&d->cie_info)))
d->state = state_error;
else if (d->cie_info.z_augmentation)
{
d->state = state_seeing_aug_size;
d->aug_size = 0;
d->aug_shift = 0;
}
else
d->state = state_wait_loc4;
break;
case state_seeing_aug_size:
/* Bytes == -1 means this comes from an leb128 directive. */
if ((int)*pnbytes == -1 && exp->X_op == O_constant)
{
d->aug_size = exp->X_add_number;
d->state = state_skipping_aug;
}
else if (*pnbytes == 1 && exp->X_op == O_constant)
{
unsigned char byte = exp->X_add_number;
d->aug_size |= (byte & 0x7f) << d->aug_shift;
d->aug_shift += 7;
if ((byte & 0x80) == 0)
d->state = state_skipping_aug;
}
else
d->state = state_error;
if (d->state == state_skipping_aug && d->aug_size == 0)
d->state = state_wait_loc4;
break;
case state_skipping_aug:
if ((int)*pnbytes < 0)
d->state = state_error;
else
{
int left = (d->aug_size -= *pnbytes);
if (left == 0)
d->state = state_wait_loc4;
else if (left < 0)
d->state = state_error;
}
break;
case state_wait_loc4:
if (*pnbytes == 1
&& exp->X_op == O_constant
&& exp->X_add_number == DW_CFA_advance_loc4)
{
/* This might be a DW_CFA_advance_loc4. Record the frag and the
position within the frag, so that we can change it later. */
frag_grow (1);
d->state = state_saw_loc4;
d->loc4_frag = frag_now;
d->loc4_fix = frag_now_fix ();
}
break;
case state_saw_loc4:
d->state = state_wait_loc4;
if (*pnbytes != 4)
break;
if (exp->X_op == O_constant)
{
/* This is a case which we can optimize. The two symbols being
subtracted were in the same frag and the expression was
reduced to a constant. We can do the optimization entirely
in this function. */
if (exp->X_add_number < 0x40)
{
d->loc4_frag->fr_literal[d->loc4_fix]
= DW_CFA_advance_loc | exp->X_add_number;
/* No more bytes needed. */
return 1;
}
else if (exp->X_add_number < 0x100)
{
d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1;
*pnbytes = 1;
}
else if (exp->X_add_number < 0x10000)
{
d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2;
*pnbytes = 2;
}
}
else if (exp->X_op == O_subtract && d->cie_info.code_alignment == 1)
{
/* This is a case we can optimize. The expression was not
reduced, so we can not finish the optimization until the end
of the assembly. We set up a variant frag which we handle
later. */
frag_var (rs_cfa, 4, 0, 1 << 3, make_expr_symbol (exp),
d->loc4_fix, (char *) d->loc4_frag);
return 1;
}
else if ((exp->X_op == O_divide
|| exp->X_op == O_right_shift)
&& d->cie_info.code_alignment > 1)
{
if (exp->X_add_symbol->bsym
&& exp->X_op_symbol->bsym
&& exp->X_add_symbol->sy_value.X_op == O_subtract
&& exp->X_op_symbol->sy_value.X_op == O_constant
&& ((exp->X_op == O_divide
? exp->X_op_symbol->sy_value.X_add_number
: (offsetT) 1 << exp->X_op_symbol->sy_value.X_add_number)
== (offsetT) d->cie_info.code_alignment))
{
/* This is a case we can optimize as well. The expression was
not reduced, so we can not finish the optimization until the
end of the assembly. We set up a variant frag which we
handle later. */
frag_var (rs_cfa, 4, 0, d->cie_info.code_alignment << 3,
make_expr_symbol (&exp->X_add_symbol->sy_value),
d->loc4_fix, (char *) d->loc4_frag);
return 1;
}
}
break;
case state_error:
/* Just skipping everything. */
break;
}
return 0;
}
/* The function estimates the size of a rs_cfa variant frag based on
the current values of the symbols. It is called before the
relaxation loop. We set fr_subtype{0:2} to the expected length. */
int
eh_frame_estimate_size_before_relax (fragS *frag)
{
offsetT diff;
int ca = frag->fr_subtype >> 3;
int ret;
diff = resolve_symbol_value (frag->fr_symbol);
gas_assert (ca > 0);
diff /= ca;
if (diff < 0x40)
ret = 0;
else if (diff < 0x100)
ret = 1;
else if (diff < 0x10000)
ret = 2;
else
ret = 4;
frag->fr_subtype = (frag->fr_subtype & ~7) | ret;
return ret;
}
/* This function relaxes a rs_cfa variant frag based on the current
values of the symbols. fr_subtype{0:2} is the current length of
the frag. This returns the change in frag length. */
int
eh_frame_relax_frag (fragS *frag)
{
int oldsize, newsize;
oldsize = frag->fr_subtype & 7;
newsize = eh_frame_estimate_size_before_relax (frag);
return newsize - oldsize;
}
/* This function converts a rs_cfa variant frag into a normal fill
frag. This is called after all relaxation has been done.
fr_subtype{0:2} will be the desired length of the frag. */
void
eh_frame_convert_frag (fragS *frag)
{
offsetT diff;
fragS *loc4_frag;
int loc4_fix, ca;
loc4_frag = (fragS *) frag->fr_opcode;
loc4_fix = (int) frag->fr_offset;
diff = resolve_symbol_value (frag->fr_symbol);
ca = frag->fr_subtype >> 3;
gas_assert (ca > 0);
diff /= ca;
switch (frag->fr_subtype & 7)
{
case 0:
gas_assert (diff < 0x40);
loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | diff;
break;
case 1:
gas_assert (diff < 0x100);
loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1;
frag->fr_literal[frag->fr_fix] = diff;
break;
case 2:
gas_assert (diff < 0x10000);
loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2;
md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
break;
default:
md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
break;
}
frag->fr_fix += frag->fr_subtype & 7;
frag->fr_type = rs_fill;
frag->fr_subtype = 0;
frag->fr_offset = 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,189 @@
/* expr.h -> header file for expr.c
Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/*
* By popular demand, we define a struct to represent an expression.
* This will no doubt mutate as expressions become baroque.
*
* Currently, we support expressions like "foo OP bar + 42". In other
* words we permit a (possibly undefined) symbol, a (possibly
* undefined) symbol and the operation used to combine the symbols,
* and an (absolute) augend. RMS says this is so we can have 1-pass
* assembly for any compiler emissions, and a 'case' statement might
* emit 'undefined1 - undefined2'.
*
* The type of an expression used to be stored as a segment. That got
* confusing because it overloaded the concept of a segment. I added
* an operator field, instead.
*/
/* This is the type of an expression. The operator types are also
used while parsing an expression.
NOTE: This enumeration must match the op_rank array in expr.c. */
typedef enum {
/* An illegal expression. */
O_illegal,
/* A nonexistent expression. */
O_absent,
/* X_add_number (a constant expression). */
O_constant,
/* X_add_symbol + X_add_number. */
O_symbol,
/* X_add_symbol + X_add_number - the base address of the image. */
O_symbol_rva,
/* A register (X_add_number is register number). */
O_register,
/* A big value. If X_add_number is negative or 0, the value is in
generic_floating_point_number. Otherwise the value is in
generic_bignum, and X_add_number is the number of LITTLENUMs in
the value. */
O_big,
/* (- X_add_symbol) + X_add_number. */
O_uminus,
/* (~ X_add_symbol) + X_add_number. */
O_bit_not,
/* (! X_add_symbol) + X_add_number. */
O_logical_not,
/* (X_add_symbol * X_op_symbol) + X_add_number. */
O_multiply,
/* (X_add_symbol / X_op_symbol) + X_add_number. */
O_divide,
/* (X_add_symbol % X_op_symbol) + X_add_number. */
O_modulus,
/* (X_add_symbol << X_op_symbol) + X_add_number. */
O_left_shift,
/* (X_add_symbol >> X_op_symbol) + X_add_number. */
O_right_shift,
/* (X_add_symbol | X_op_symbol) + X_add_number. */
O_bit_inclusive_or,
/* (X_add_symbol |~ X_op_symbol) + X_add_number. */
O_bit_or_not,
/* (X_add_symbol ^ X_op_symbol) + X_add_number. */
O_bit_exclusive_or,
/* (X_add_symbol & X_op_symbol) + X_add_number. */
O_bit_and,
/* (X_add_symbol + X_op_symbol) + X_add_number. */
O_add,
/* (X_add_symbol - X_op_symbol) + X_add_number. */
O_subtract,
/* (X_add_symbol == X_op_symbol) + X_add_number. */
O_eq,
/* (X_add_symbol != X_op_symbol) + X_add_number. */
O_ne,
/* (X_add_symbol < X_op_symbol) + X_add_number. */
O_lt,
/* (X_add_symbol <= X_op_symbol) + X_add_number. */
O_le,
/* (X_add_symbol >= X_op_symbol) + X_add_number. */
O_ge,
/* (X_add_symbol > X_op_symbol) + X_add_number. */
O_gt,
/* (X_add_symbol && X_op_symbol) + X_add_number. */
O_logical_and,
/* (X_add_symbol || X_op_symbol) + X_add_number. */
O_logical_or,
/* X_op_symbol [ X_add_symbol ] */
O_index,
/* machine dependent operators */
O_md1, O_md2, O_md3, O_md4, O_md5, O_md6, O_md7, O_md8,
O_md9, O_md10, O_md11, O_md12, O_md13, O_md14, O_md15, O_md16,
O_md17, O_md18, O_md19, O_md20, O_md21, O_md22, O_md23, O_md24,
O_md25, O_md26, O_md27, O_md28, O_md29, O_md30, O_md31, O_md32,
/* this must be the largest value */
O_max
} operatorT;
typedef struct expressionS {
/* The main symbol. */
symbolS *X_add_symbol;
/* The second symbol, if needed. */
symbolS *X_op_symbol;
/* A number to add. */
offsetT X_add_number;
/* The type of the expression. We can't assume that an arbitrary
compiler can handle a bitfield of enum type. FIXME: We could
check this using autoconf. */
#ifdef __GNUC__
operatorT X_op : 8;
#else
unsigned char X_op;
#endif
/* Non-zero if X_add_number should be regarded as unsigned. This is
only valid for O_constant expressions. It is only used when an
O_constant must be extended into a bignum (i.e., it is not used
when performing arithmetic on these values).
FIXME: This field is not set very reliably. */
unsigned int X_unsigned : 1;
/* This is used to implement "word size + 1 bit" arithmetic, so that e.g.
expressions used with .sleb128 directives can use the full range available
for an unsigned word, but can also properly represent all values of a
signed word. */
unsigned int X_extrabit : 1;
/* 7 additional bits can be defined if needed. */
/* Machine dependent field */
unsigned short X_md;
} expressionS;
enum expr_mode
{
expr_evaluate,
expr_normal,
expr_defer
};
/* "result" should be type (expressionS *). */
#define expression(result) expr (0, result, expr_normal)
#define expression_and_evaluate(result) expr (0, result, expr_evaluate)
#define deferred_expression(result) expr (0, result, expr_defer)
/* If an expression is O_big, look here for its value. These common
data may be clobbered whenever expr() is called. */
/* Flonums returned here. Big enough to hold most precise flonum. */
extern FLONUM_TYPE generic_floating_point_number;
/* Bignums returned here. */
extern LITTLENUM_TYPE generic_bignum[];
/* Number of littlenums in above. */
#define SIZE_OF_LARGE_NUMBER (20)
typedef char operator_rankT;
extern char get_symbol_end (void);
extern void expr_begin (void);
extern void expr_set_precedence (void);
extern void expr_set_rank (operatorT, operator_rankT);
extern void add_to_result (expressionS *, offsetT, int);
extern void subtract_from_result (expressionS *, offsetT, int);
extern segT expr (int, expressionS *, enum expr_mode);
extern unsigned int get_single_number (void);
extern symbolS *make_expr_symbol (expressionS * expressionP);
extern int expr_symbol_where (symbolS *, char **, unsigned int *);
extern void current_location (expressionS *);
extern symbolS *expr_build_uconstant (offsetT);
extern symbolS *expr_build_dot (void);
int resolve_expression (expressionS *);

View File

@ -0,0 +1,71 @@
/* flonum_copy.c - copy a flonum
Copyright 1987, 1990, 1991, 1992, 1993, 2000, 2003, 2005, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
void
flonum_copy (FLONUM_TYPE *in, FLONUM_TYPE *out)
{
unsigned int in_length; /* 0 origin */
unsigned int out_length; /* 0 origin */
out->sign = in->sign;
in_length = in->leader - in->low;
if (in->leader < in->low)
{
out->leader = out->low - 1; /* 0.0 case */
}
else
{
out_length = out->high - out->low;
/* Assume no GAPS in packing of littlenums.
I.e. sizeof(array) == sizeof(element) * number_of_elements. */
if (in_length <= out_length)
{
{
/* For defensive programming, zero any high-order
littlenums we don't need. This is destroying evidence
and wasting time, so why bother??? */
if (in_length < out_length)
{
memset ((char *) (out->low + in_length + 1), '\0',
out_length - in_length);
}
}
memcpy ((void *) (out->low), (void *) (in->low),
((in_length + 1) * sizeof (LITTLENUM_TYPE)));
out->exponent = in->exponent;
out->leader = in->leader - in->low + out->low;
}
else
{
int shorten; /* 1-origin. Number of littlenums we drop. */
shorten = in_length - out_length;
/* Assume out_length >= 0 ! */
memcpy ((void *) (out->low), (void *) (in->low + shorten),
((out_length + 1) * sizeof (LITTLENUM_TYPE)));
out->leader = out->high;
out->exponent = in->exponent + shorten;
}
} /* if any significant bits */
}

View File

@ -0,0 +1,228 @@
/* flonum_const.c - Useful Flonum constants
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 2000, 2002,
2005, 2007 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "ansidecl.h"
#include "flonum.h"
/* JF: I added the last entry to this table, and I'm not
sure if its right or not. Could go either way. I wish
I really understood this stuff. */
const int table_size_of_flonum_powers_of_ten = 13;
static const LITTLENUM_TYPE zero[] = {
1
};
/***********************************************************************\
* *
* Warning: the low order bits may be WRONG here. *
* I took this from a suspect bc(1) script. *
* "minus_X"[] is supposed to be 10^(2^-X) expressed in base 2^16. *
* The radix point is just AFTER the highest element of the [] *
* *
* Because bc rounds DOWN for printing (I think), the lowest *
* significance littlenums should probably have 1 added to them. *
* *
\***********************************************************************/
/* JF: If this equals 6553/(2^16)+39321/(2^32)+... it approaches .1 */
static const LITTLENUM_TYPE minus_1[] = {
39322, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321,
39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 6553
};
static const LITTLENUM_TYPE plus_1[] = {
10
};
/* JF: If this equals 655/(2^16) + 23592/(2^32) + ... it approaches .01 */
static const LITTLENUM_TYPE minus_2[] = {
10486, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 49807,
10485, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 655
};
static const LITTLENUM_TYPE plus_2[] = {
100
};
/* This approaches .0001 */
static const LITTLENUM_TYPE minus_3[] = {
52534, 20027, 37329, 65116, 64067, 60397, 14784, 18979, 33659, 19503,
2726, 9542, 629, 2202, 40475, 10590, 4299, 47815, 36280, 6
};
static const LITTLENUM_TYPE plus_3[] = {
10000
};
/* JF: this approaches 1e-8 */
static const LITTLENUM_TYPE minus_4[] = {
22517, 49501, 54293, 19424, 60699, 6716, 24348, 22618, 23904, 21327,
3919, 44703, 19149, 28803, 48959, 6259, 50273, 62237, 42
};
/* This equals 1525 * 2^16 + 57600 */
static const LITTLENUM_TYPE plus_4[] = {
57600, 1525
};
/* This approaches 1e-16 */
static const LITTLENUM_TYPE minus_5[] = {
22199, 45957, 17005, 26266, 10526, 16260, 55017, 35680, 40443, 19789,
17356, 30195, 55905, 28426, 63010, 44197, 1844
};
static const LITTLENUM_TYPE plus_5[] = {
28609, 34546, 35
};
static const LITTLENUM_TYPE minus_6[] = {
30926, 26518, 13110, 43018, 54982, 48258, 24658, 15209, 63366, 11929,
20069, 43857, 60487, 51
};
static const LITTLENUM_TYPE plus_6[] = {
61313, 34220, 16731, 11629, 1262
};
static const LITTLENUM_TYPE minus_7[] = {
29819, 14733, 21490, 40602, 31315, 65186, 2695
};
static const LITTLENUM_TYPE plus_7[] = {
7937, 49002, 60772, 28216, 38893, 55975, 63988, 59711, 20227, 24
};
static const LITTLENUM_TYPE minus_8[] = {
27579, 64807, 12543, 794, 13907, 61297, 12013, 64360, 15961, 20566,
24178, 15922, 59427, 110
};
static const LITTLENUM_TYPE plus_8[] = {
15873, 11925, 39177, 991, 14589, 3861, 58415, 9076, 62956, 54223,
56328, 50180, 45274, 48333, 32537, 42547, 9731, 59679, 590
};
static const LITTLENUM_TYPE minus_9[] = {
11042, 8464, 58971, 63429, 6022, 63485, 5500, 53464, 47545, 50068,
56988, 22819, 49708, 54493, 9920, 47667, 40409, 35764, 10383, 54466,
32702, 17493, 32420, 34382, 22750, 20681, 12300
};
static const LITTLENUM_TYPE plus_9[] = {
20678, 27614, 28272, 53066, 55311, 54677, 29038, 9906, 26288, 44486,
13860, 7445, 54106, 15426, 21518, 25599, 29632, 52309, 61207, 26105,
10482, 21948, 51191, 32988, 60892, 62574, 61390, 24540, 21495, 5
};
static const LITTLENUM_TYPE minus_10[] = {
6214, 48771, 23471, 30163, 31763, 38013, 57001, 11770, 18263, 36366,
20742, 45086, 56969, 53231, 37856, 55814, 38057, 15692, 46761, 8713,
6102, 20083, 8269, 11839, 11571, 50963, 15649, 11698, 40675, 2308
};
static const LITTLENUM_TYPE plus_10[] = {
63839, 36576, 45712, 44516, 37803, 29482, 4966, 30556, 37961, 23310,
27070, 44972, 29507, 48257, 45209, 7494, 17831, 38728, 41577, 29443,
36016, 7955, 35339, 35479, 36011, 14553, 49618, 5588, 25396, 28
};
static const LITTLENUM_TYPE minus_11[] = {
16663, 56882, 61983, 7804, 36555, 32060, 34502, 1000, 14356, 21681,
6605, 34767, 51411, 59048, 53614, 39850, 30079, 6496, 6846, 26841,
40778, 19578, 59899, 44085, 54016, 24259, 11232, 21229, 21313, 81
};
static const LITTLENUM_TYPE plus_11[] = {
92, 9054, 62707, 17993, 7821, 56838, 13992, 21321, 29637, 48426,
42982, 38668, 49574, 28820, 18200, 18927, 53979, 16219, 37484, 2516,
44642, 14665, 11587, 41926, 13556, 23956, 54320, 6661, 55766, 805
};
static const LITTLENUM_TYPE minus_12[] = {
33202, 45969, 58804, 56734, 16482, 26007, 44984, 49334, 31007, 32944,
44517, 63329, 47131, 15291, 59465, 2264, 23218, 11829, 59771, 38798,
31051, 28748, 23129, 40541, 41562, 35108, 50620, 59014, 51817, 6613
};
static const LITTLENUM_TYPE plus_12[] = {
10098, 37922, 58070, 7432, 10470, 63465, 23718, 62190, 47420, 7009,
38443, 4587, 45596, 38472, 52129, 52779, 29012, 13559, 48688, 31678,
41753, 58662, 10668, 36067, 29906, 56906, 21461, 46556, 59571, 9
};
static const LITTLENUM_TYPE minus_13[] = {
45309, 27592, 37144, 34637, 34328, 41671, 34620, 24135, 53401, 22112,
21576, 45147, 39310, 44051, 48572, 3676, 46544, 59768, 33350, 2323,
49524, 61568, 3903, 36487, 36356, 30903, 14975, 9035, 29715, 667
};
static const LITTLENUM_TYPE plus_13[] = {
18788, 16960, 6318, 45685, 55400, 46230, 35794, 25588, 7253, 55541,
49716, 59760, 63592, 8191, 63765, 58530, 44667, 13294, 10001, 55586,
47887, 18738, 9509, 40896, 42506, 52580, 4171, 325, 12329, 98
};
/* Shut up complaints about differing pointer types. They only differ
in the const attribute, but there isn't any easy way to do this
*/
#define X (LITTLENUM_TYPE *)
const FLONUM_TYPE flonum_negative_powers_of_ten[] = {
{X zero, X zero, X zero, 0, '+'},
{X minus_1, X minus_1 + 19, X minus_1 + 19, -20, '+'},
{X minus_2, X minus_2 + 19, X minus_2 + 19, -20, '+'},
{X minus_3, X minus_3 + 19, X minus_3 + 19, -20, '+'},
{X minus_4, X minus_4 + 18, X minus_4 + 18, -20, '+'},
{X minus_5, X minus_5 + 16, X minus_5 + 16, -20, '+'},
{X minus_6, X minus_6 + 13, X minus_6 + 13, -20, '+'},
{X minus_7, X minus_7 + 6, X minus_7 + 6, -20, '+'},
{X minus_8, X minus_8 + 13, X minus_8 + 13, -40, '+'},
{X minus_9, X minus_9 + 26, X minus_9 + 26, -80, '+'},
{X minus_10, X minus_10 + 29, X minus_10 + 29, -136, '+'},
{X minus_11, X minus_11 + 29, X minus_11 + 29, -242, '+'},
{X minus_12, X minus_12 + 29, X minus_12 + 29, -455, '+'},
{X minus_13, X minus_13 + 29, X minus_13 + 29, -880, '+'},
};
const FLONUM_TYPE flonum_positive_powers_of_ten[] = {
{X zero, X zero, X zero, 0, '+'},
{X plus_1, X plus_1 + 0, X plus_1 + 0, 0, '+'},
{X plus_2, X plus_2 + 0, X plus_2 + 0, 0, '+'},
{X plus_3, X plus_3 + 0, X plus_3 + 0, 0, '+'},
{X plus_4, X plus_4 + 1, X plus_4 + 1, 0, '+'},
{X plus_5, X plus_5 + 2, X plus_5 + 2, 1, '+'},
{X plus_6, X plus_6 + 4, X plus_6 + 4, 2, '+'},
{X plus_7, X plus_7 + 9, X plus_7 + 9, 4, '+'},
{X plus_8, X plus_8 + 18, X plus_8 + 18, 8, '+'},
{X plus_9, X plus_9 + 29, X plus_9 + 29, 24, '+'},
{X plus_10, X plus_10 + 29, X plus_10 + 29, 77, '+'},
{X plus_11, X plus_11 + 29, X plus_11 + 29, 183, '+'},
{X plus_12, X plus_12 + 29, X plus_12 + 29, 396, '+'},
{X plus_13, X plus_13 + 29, X plus_13 + 29, 821, '+'},
};
#ifdef VMS
void
dummy1 ()
{
}
#endif

View File

@ -0,0 +1,188 @@
/* flonum_mult.c - multiply two flonums
Copyright 1987, 1990, 1991, 1992, 1995, 2000, 2002, 2003, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "ansidecl.h"
#include "flonum.h"
/* plan for a . b => p(roduct)
+-------+-------+-/ /-+-------+-------+
| a | a | ... | a | a |
| A | A-1 | | 1 | 0 |
+-------+-------+-/ /-+-------+-------+
+-------+-------+-/ /-+-------+-------+
| b | b | ... | b | b |
| B | B-1 | | 1 | 0 |
+-------+-------+-/ /-+-------+-------+
+-------+-------+-/ /-+-------+-/ /-+-------+-------+
| p | p | ... | p | ... | p | p |
| A+B+1| A+B | | N | | 1 | 0 |
+-------+-------+-/ /-+-------+-/ /-+-------+-------+
/^\
(carry) a .b ... | ... a .b a .b
A B | 0 1 0 0
|
... | ... a .b
| 1 0
|
| ...
|
|
|
| ___
| \
+----- P = > a .b
N /__ i j
N = 0 ... A+B
for all i,j where i+j=N
[i,j integers > 0]
a[], b[], p[] may not intersect.
Zero length factors signify 0 significant bits: treat as 0.0.
0.0 factors do the right thing.
Zero length product OK.
I chose the ForTran accent "foo[bar]" instead of the C accent "*garply"
because I felt the ForTran way was more intuitive. The C way would
probably yield better code on most C compilers. Dean Elsner.
(C style also gives deeper insight [to me] ... oh well ...) */
void
flonum_multip (const FLONUM_TYPE *a, const FLONUM_TYPE *b,
FLONUM_TYPE *product)
{
int size_of_a; /* 0 origin */
int size_of_b; /* 0 origin */
int size_of_product; /* 0 origin */
int size_of_sum; /* 0 origin */
int extra_product_positions; /* 1 origin */
unsigned long work;
unsigned long carry;
long exponent;
LITTLENUM_TYPE *q;
long significant; /* TRUE when we emit a non-0 littlenum */
/* ForTran accent follows. */
int P; /* Scan product low-order -> high. */
int N; /* As in sum above. */
int A; /* Which [] of a? */
int B; /* Which [] of b? */
if ((a->sign != '-' && a->sign != '+')
|| (b->sign != '-' && b->sign != '+'))
{
/* Got to fail somehow. Any suggestions? */
product->sign = 0;
return;
}
product->sign = (a->sign == b->sign) ? '+' : '-';
size_of_a = a->leader - a->low;
size_of_b = b->leader - b->low;
exponent = a->exponent + b->exponent;
size_of_product = product->high - product->low;
size_of_sum = size_of_a + size_of_b;
extra_product_positions = size_of_product - size_of_sum;
if (extra_product_positions < 0)
{
P = extra_product_positions; /* P < 0 */
exponent -= extra_product_positions; /* Increases exponent. */
}
else
{
P = 0;
}
carry = 0;
significant = 0;
for (N = 0; N <= size_of_sum; N++)
{
work = carry;
carry = 0;
for (A = 0; A <= N; A++)
{
B = N - A;
if (A <= size_of_a && B <= size_of_b && B >= 0)
{
#ifdef TRACE
printf ("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n",
A, a->low[A], B, b->low[B], work);
#endif
/* Watch out for sign extension! Without the casts, on
the DEC Alpha, the multiplication result is *signed*
int, which gets sign-extended to convert to the
unsigned long! */
work += (unsigned long) a->low[A] * (unsigned long) b->low[B];
carry += work >> LITTLENUM_NUMBER_OF_BITS;
work &= LITTLENUM_MASK;
#ifdef TRACE
printf ("work=%08x carry=%04x\n", work, carry);
#endif
}
}
significant |= work;
if (significant || P < 0)
{
if (P >= 0)
{
product->low[P] = work;
#ifdef TRACE
printf ("P=%d. work[p]:=%04x\n", P, work);
#endif
}
P++;
}
else
{
extra_product_positions++;
exponent++;
}
}
/* [P]-> position # size_of_sum + 1.
This is where 'carry' should go. */
#ifdef TRACE
printf ("final carry =%04x\n", carry);
#endif
if (carry)
{
if (extra_product_positions > 0)
product->low[P] = carry;
else
{
/* No room at high order for carry littlenum. */
/* Shift right 1 to make room for most significant littlenum. */
exponent++;
P--;
for (q = product->low + P; q >= product->low; q--)
{
work = *q;
*q = carry;
carry = work;
}
}
}
else
P--;
product->leader = product->low + P;
product->exponent = exponent;
}

View File

@ -0,0 +1,102 @@
/* flonum.h - Floating point package
Copyright 1987, 1990, 1991, 1992, 1994, 1996, 2000, 2003, 2005, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/***********************************************************************\
* *
* Arbitrary-precision floating point arithmetic. *
* *
* *
* Notation: a floating point number is expressed as *
* MANTISSA * (2 ** EXPONENT). *
* *
* If this offends more traditional mathematicians, then *
* please tell me your nomenclature for flonums! *
* *
\***********************************************************************/
#include "bignum.h"
/***********************************************************************\
* *
* Variable precision floating point numbers. *
* *
* Exponent is the place value of the low littlenum. E.g.: *
* If 0: low points to the units littlenum. *
* If 1: low points to the LITTLENUM_RADIX littlenum. *
* If -1: low points to the 1/LITTLENUM_RADIX littlenum. *
* *
\***********************************************************************/
/* JF: A sign value of 0 means we have been asked to assemble NaN
A sign value of 'P' means we've been asked to assemble +Inf
A sign value of 'N' means we've been asked to assemble -Inf
*/
struct FLONUM_STRUCT {
LITTLENUM_TYPE *low; /* low order littlenum of a bignum */
LITTLENUM_TYPE *high; /* high order littlenum of a bignum */
LITTLENUM_TYPE *leader; /* -> 1st non-zero littlenum */
/* If flonum is 0.0, leader==low-1 */
long exponent; /* base LITTLENUM_RADIX */
char sign; /* '+' or '-' */
};
typedef struct FLONUM_STRUCT FLONUM_TYPE;
/***********************************************************************\
* *
* Since we can (& do) meet with exponents like 10^5000, it *
* is silly to make a table of ~ 10,000 entries, one for each *
* power of 10. We keep a table where item [n] is a struct *
* FLONUM_FLOATING_POINT representing 10^(2^n). We then *
* multiply appropriate entries from this table to get any *
* particular power of 10. For the example of 10^5000, a table *
* of just 25 entries suffices: 10^(2^-12)...10^(2^+12). *
* *
\***********************************************************************/
extern const FLONUM_TYPE flonum_positive_powers_of_ten[];
extern const FLONUM_TYPE flonum_negative_powers_of_ten[];
extern const int table_size_of_flonum_powers_of_ten;
/* Flonum_XXX_powers_of_ten[] table has legal indices from 0 to
+ this number inclusive. */
/***********************************************************************\
* *
* Declare worker functions. *
* *
\***********************************************************************/
int atof_generic (char **address_of_string_pointer,
const char *string_of_decimal_marks,
const char *string_of_decimal_exponent_marks,
FLONUM_TYPE * address_of_generic_floating_point_number);
void flonum_copy (FLONUM_TYPE * in, FLONUM_TYPE * out);
void flonum_multip (const FLONUM_TYPE * a, const FLONUM_TYPE * b,
FLONUM_TYPE * product);
/***********************************************************************\
* *
* Declare error codes. *
* *
\***********************************************************************/
#define ERROR_EXPONENT_OVERFLOW (2)

View File

@ -0,0 +1,445 @@
/* frags.c - manage frags -
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "subsegs.h"
#include "obstack.h"
extern fragS zero_address_frag;
extern fragS predefined_address_frag;
/* Initialization for frag routines. */
void
frag_init (void)
{
zero_address_frag.fr_type = rs_fill;
predefined_address_frag.fr_type = rs_fill;
}
/* Check that we're not trying to assemble into a section that can't
allocate frags (currently, this is only possible in the absolute
section), or into an mri common. */
static void
frag_alloc_check (const struct obstack *ob)
{
if (ob->chunk_size == 0)
{
as_bad (_("attempt to allocate data in absolute section"));
subseg_set (text_section, 0);
}
if (mri_common_symbol != NULL)
{
as_bad (_("attempt to allocate data in common section"));
mri_common_symbol = NULL;
}
}
/* Allocate a frag on the specified obstack.
Call this routine from everywhere else, so that all the weird alignment
hackery can be done in just one place. */
fragS *
frag_alloc (struct obstack *ob)
{
fragS *ptr;
int oalign;
(void) obstack_alloc (ob, 0);
oalign = obstack_alignment_mask (ob);
obstack_alignment_mask (ob) = 0;
ptr = (fragS *) obstack_alloc (ob, SIZEOF_STRUCT_FRAG);
obstack_alignment_mask (ob) = oalign;
memset (ptr, 0, SIZEOF_STRUCT_FRAG);
return ptr;
}
/* Try to augment current frag by nchars chars.
If there is no room, close of the current frag with a ".fill 0"
and begin a new frag. Unless the new frag has nchars chars available
do not return. Do not set up any fields of *now_frag. */
void
frag_grow (unsigned int nchars)
{
if (obstack_room (&frchain_now->frch_obstack) < nchars)
{
long oldc;
long newc;
/* Try to allocate a bit more than needed right now. But don't do
this if we would waste too much memory. Especially necessary
for extremely big (like 2GB initialized) frags. */
if (nchars < 0x10000)
newc = 2 * nchars;
else
newc = nchars + 0x10000;
newc += SIZEOF_STRUCT_FRAG;
/* Check for possible overflow. */
if (newc < 0)
as_fatal (_("can't extend frag %u chars"), nchars);
/* Force to allocate at least NEWC bytes, but not less than the
default. */
oldc = obstack_chunk_size (&frchain_now->frch_obstack);
if (newc > oldc)
obstack_chunk_size (&frchain_now->frch_obstack) = newc;
while (obstack_room (&frchain_now->frch_obstack) < nchars)
{
/* Not enough room in this frag. Close it and start a new one.
This must be done in a loop because the created frag may not
be big enough if the current obstack chunk is used. */
frag_wane (frag_now);
frag_new (0);
}
/* Restore the old chunk size. */
obstack_chunk_size (&frchain_now->frch_obstack) = oldc;
}
}
/* Call this to close off a completed frag, and start up a new (empty)
frag, in the same subsegment as the old frag.
[frchain_now remains the same but frag_now is updated.]
Because this calculates the correct value of fr_fix by
looking at the obstack 'frags', it needs to know how many
characters at the end of the old frag belong to the maximal
variable part; The rest must belong to fr_fix.
It doesn't actually set up the old frag's fr_var. You may have
set fr_var == 1, but allocated 10 chars to the end of the frag;
In this case you pass old_frags_var_max_size == 10.
In fact, you may use fr_var for something totally unrelated to the
size of the variable part of the frag; None of the generic frag
handling code makes use of fr_var.
Make a new frag, initialising some components. Link new frag at end
of frchain_now. */
void
frag_new (int old_frags_var_max_size
/* Number of chars (already allocated on obstack frags) in
variable_length part of frag. */)
{
fragS *former_last_fragP;
frchainS *frchP;
gas_assert (frchain_now->frch_last == frag_now);
/* Fix up old frag's fr_fix. */
frag_now->fr_fix = frag_now_fix_octets () - old_frags_var_max_size;
/* Make sure its type is valid. */
gas_assert (frag_now->fr_type != 0);
/* This will align the obstack so the next struct we allocate on it
will begin at a correct boundary. */
obstack_finish (&frchain_now->frch_obstack);
frchP = frchain_now;
know (frchP);
former_last_fragP = frchP->frch_last;
gas_assert (former_last_fragP != 0);
gas_assert (former_last_fragP == frag_now);
frag_now = frag_alloc (&frchP->frch_obstack);
as_where (&frag_now->fr_file, &frag_now->fr_line);
/* Generally, frag_now->points to an address rounded up to next
alignment. However, characters will add to obstack frags
IMMEDIATELY after the struct frag, even if they are not starting
at an alignment address. */
former_last_fragP->fr_next = frag_now;
frchP->frch_last = frag_now;
#ifndef NO_LISTING
{
extern struct list_info_struct *listing_tail;
frag_now->line = listing_tail;
}
#endif
gas_assert (frchain_now->frch_last == frag_now);
frag_now->fr_next = NULL;
}
/* Start a new frag unless we have n more chars of room in the current frag.
Close off the old frag with a .fill 0.
Return the address of the 1st char to write into. Advance
frag_now_growth past the new chars. */
char *
frag_more (int nchars)
{
register char *retval;
frag_alloc_check (&frchain_now->frch_obstack);
frag_grow (nchars);
retval = obstack_next_free (&frchain_now->frch_obstack);
obstack_blank_fast (&frchain_now->frch_obstack, nchars);
return (retval);
}
/* Close the current frag, setting its fields for a relaxable frag. Start a
new frag. */
static void
frag_var_init (relax_stateT type, int max_chars, int var,
relax_substateT subtype, symbolS *symbol, offsetT offset,
char *opcode)
{
frag_now->fr_var = var;
frag_now->fr_type = type;
frag_now->fr_subtype = subtype;
frag_now->fr_symbol = symbol;
frag_now->fr_offset = offset;
frag_now->fr_opcode = opcode;
#ifdef USING_CGEN
frag_now->fr_cgen.insn = 0;
frag_now->fr_cgen.opindex = 0;
frag_now->fr_cgen.opinfo = 0;
#endif
#ifdef TC_FRAG_INIT
TC_FRAG_INIT (frag_now);
#endif
as_where (&frag_now->fr_file, &frag_now->fr_line);
frag_new (max_chars);
}
/* Start a new frag unless we have max_chars more chars of room in the
current frag. Close off the old frag with a .fill 0.
Set up a machine_dependent relaxable frag, then start a new frag.
Return the address of the 1st char of the var part of the old frag
to write into. */
char *
frag_var (relax_stateT type, int max_chars, int var, relax_substateT subtype,
symbolS *symbol, offsetT offset, char *opcode)
{
register char *retval;
frag_grow (max_chars);
retval = obstack_next_free (&frchain_now->frch_obstack);
obstack_blank_fast (&frchain_now->frch_obstack, max_chars);
frag_var_init (type, max_chars, var, subtype, symbol, offset, opcode);
return retval;
}
/* OVE: This variant of frag_var assumes that space for the tail has been
allocated by caller.
No call to frag_grow is done. */
char *
frag_variant (relax_stateT type, int max_chars, int var,
relax_substateT subtype, symbolS *symbol, offsetT offset,
char *opcode)
{
register char *retval;
retval = obstack_next_free (&frchain_now->frch_obstack);
frag_var_init (type, max_chars, var, subtype, symbol, offset, opcode);
return retval;
}
/* Reduce the variable end of a frag to a harmless state. */
void
frag_wane (register fragS *fragP)
{
fragP->fr_type = rs_fill;
fragP->fr_offset = 0;
fragP->fr_var = 0;
}
/* Return the number of bytes by which the current frag can be grown. */
int
frag_room (void)
{
return obstack_room (&frchain_now->frch_obstack);
}
/* Make an alignment frag. The size of this frag will be adjusted to
force the next frag to have the appropriate alignment. ALIGNMENT
is the power of two to which to align. FILL_CHARACTER is the
character to use to fill in any bytes which are skipped. MAX is
the maximum number of characters to skip when doing the alignment,
or 0 if there is no maximum. */
void
frag_align (int alignment, int fill_character, int max)
{
if (now_seg == absolute_section)
{
addressT new_off;
addressT mask;
mask = (~(addressT) 0) << alignment;
new_off = (abs_section_offset + ~mask) & mask;
if (max == 0 || new_off - abs_section_offset <= (addressT) max)
abs_section_offset = new_off;
}
else
{
char *p;
p = frag_var (rs_align, 1, 1, (relax_substateT) max,
(symbolS *) 0, (offsetT) alignment, (char *) 0);
*p = fill_character;
}
}
/* Make an alignment frag like frag_align, but fill with a repeating
pattern rather than a single byte. ALIGNMENT is the power of two
to which to align. FILL_PATTERN is the fill pattern to repeat in
the bytes which are skipped. N_FILL is the number of bytes in
FILL_PATTERN. MAX is the maximum number of characters to skip when
doing the alignment, or 0 if there is no maximum. */
void
frag_align_pattern (int alignment, const char *fill_pattern,
int n_fill, int max)
{
char *p;
p = frag_var (rs_align, n_fill, n_fill, (relax_substateT) max,
(symbolS *) 0, (offsetT) alignment, (char *) 0);
memcpy (p, fill_pattern, n_fill);
}
/* The NOP_OPCODE is for the alignment fill value. Fill it with a nop
instruction so that the disassembler does not choke on it. */
#ifndef NOP_OPCODE
#define NOP_OPCODE 0x00
#endif
/* Use this to restrict the amount of memory allocated for representing
the alignment code. Needs to be large enough to hold any fixed sized
prologue plus the replicating portion. */
#ifndef MAX_MEM_FOR_RS_ALIGN_CODE
/* Assume that if HANDLE_ALIGN is not defined then no special action
is required to code fill, which means that we get just repeat the
one NOP_OPCODE byte. */
# ifndef HANDLE_ALIGN
# define MAX_MEM_FOR_RS_ALIGN_CODE 1
# else
# define MAX_MEM_FOR_RS_ALIGN_CODE ((1 << alignment) - 1)
# endif
#endif
void
frag_align_code (int alignment, int max)
{
char *p;
p = frag_var (rs_align_code, MAX_MEM_FOR_RS_ALIGN_CODE, 1,
(relax_substateT) max, (symbolS *) 0,
(offsetT) alignment, (char *) 0);
*p = NOP_OPCODE;
}
addressT
frag_now_fix_octets (void)
{
if (now_seg == absolute_section)
return abs_section_offset;
return ((char *) obstack_next_free (&frchain_now->frch_obstack)
- frag_now->fr_literal);
}
addressT
frag_now_fix (void)
{
return frag_now_fix_octets () / OCTETS_PER_BYTE;
}
void
frag_append_1_char (int datum)
{
frag_alloc_check (&frchain_now->frch_obstack);
if (obstack_room (&frchain_now->frch_obstack) <= 1)
{
frag_wane (frag_now);
frag_new (0);
}
obstack_1grow (&frchain_now->frch_obstack, datum);
}
/* Return TRUE if FRAG1 and FRAG2 have a fixed relationship between
their start addresses. Set OFFSET to the difference in address
not already accounted for in the frag FR_ADDRESS. */
bfd_boolean
frag_offset_fixed_p (const fragS *frag1, const fragS *frag2, offsetT *offset)
{
const fragS *frag;
offsetT off;
/* Start with offset initialised to difference between the two frags.
Prior to assigning frag addresses this will be zero. */
off = frag1->fr_address - frag2->fr_address;
if (frag1 == frag2)
{
*offset = off;
return TRUE;
}
/* Maybe frag2 is after frag1. */
frag = frag1;
while (frag->fr_type == rs_fill)
{
off += frag->fr_fix + frag->fr_offset * frag->fr_var;
frag = frag->fr_next;
if (frag == NULL)
break;
if (frag == frag2)
{
*offset = off;
return TRUE;
}
}
/* Maybe frag1 is after frag2. */
off = frag1->fr_address - frag2->fr_address;
frag = frag2;
while (frag->fr_type == rs_fill)
{
off -= frag->fr_fix + frag->fr_offset * frag->fr_var;
frag = frag->fr_next;
if (frag == NULL)
break;
if (frag == frag1)
{
*offset = off;
return TRUE;
}
}
return FALSE;
}

View File

@ -0,0 +1,160 @@
/* frags.h - Header file for the frag concept.
Copyright 1987, 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2006, 2007, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef FRAGS_H
#define FRAGS_H
struct obstack;
/* A code fragment (frag) is some known number of chars, followed by some
unknown number of chars. Typically the unknown number of chars is an
instruction address whose size is yet unknown. We always know the greatest
possible size the unknown number of chars may become, and reserve that
much room at the end of the frag.
Once created, frags do not change address during assembly.
We chain the frags in (a) forward-linked list(s). The object-file address
of the 1st char of a frag is generally not known until after relax().
Many things at assembly time describe an address by {object-file-address
of a particular frag}+offset.
BUG: it may be smarter to have a single pointer off to various different
notes for different frag kinds. See how code pans. */
struct frag {
/* Object file address (as an octet offset). */
addressT fr_address;
/* When relaxing multiple times, remember the address the frag had
in the last relax pass. */
addressT last_fr_address;
/* (Fixed) number of octets we know we have. May be 0. */
offsetT fr_fix;
/* May be used for (Variable) number of octets after above.
The generic frag handling code no longer makes any use of fr_var. */
offsetT fr_var;
/* For variable-length tail. */
offsetT fr_offset;
/* For variable-length tail. */
symbolS *fr_symbol;
/* Points to opcode low addr byte, for relaxation. */
char *fr_opcode;
/* Chain forward; ascending address order. Rooted in frch_root. */
struct frag *fr_next;
/* Where the frag was created, or where it became a variant frag. */
char *fr_file;
unsigned int fr_line;
#ifndef NO_LISTING
struct list_info_struct *line;
#endif
/* A serial number for a sequence of frags having at most one alignment
or org frag, and that at the tail of the sequence. */
unsigned int region:16;
/* Flipped each relax pass so we can easily determine whether
fr_address has been adjusted. */
unsigned int relax_marker:1;
/* Used to ensure that all insns are emitted on proper address
boundaries. */
unsigned int has_code:1;
unsigned int insn_addr:6;
/* What state is my tail in? */
relax_stateT fr_type;
relax_substateT fr_subtype;
#ifdef USING_CGEN
/* Don't include this unless using CGEN to keep frag size down. */
struct {
/* CGEN_INSN entry for this instruction. */
const struct cgen_insn *insn;
/* Index into operand table. */
int opindex;
/* Target specific data, usually reloc number. */
int opinfo;
} fr_cgen;
#endif
#ifdef TC_FRAG_TYPE
TC_FRAG_TYPE tc_frag_data;
#endif
#ifdef OBJ_FRAG_TYPE
OBJ_FRAG_TYPE obj_frag_data;
#endif
/* Data begins here. */
char fr_literal[1];
};
#define SIZEOF_STRUCT_FRAG \
((char *) zero_address_frag.fr_literal - (char *) &zero_address_frag)
/* We want to say fr_literal[0] above. */
/* Current frag we are building. This frag is incomplete. It is,
however, included in frchain_now. The fr_fix field is bogus;
instead, use frag_now_fix (). */
COMMON fragS *frag_now;
extern addressT frag_now_fix (void);
extern addressT frag_now_fix_octets (void);
/* For foreign-segment symbol fixups. */
COMMON fragS zero_address_frag;
COMMON fragS predefined_address_frag;
extern void frag_append_1_char (int);
#define FRAG_APPEND_1_CHAR(X) frag_append_1_char (X)
void frag_init (void);
fragS *frag_alloc (struct obstack *);
void frag_grow (unsigned int nchars);
char *frag_more (int nchars);
void frag_align (int alignment, int fill_character, int max);
void frag_align_pattern (int alignment, const char *fill_pattern,
int n_fill, int max);
void frag_align_code (int alignment, int max);
void frag_new (int old_frags_var_max_size);
void frag_wane (fragS * fragP);
int frag_room (void);
char *frag_variant (relax_stateT type,
int max_chars,
int var,
relax_substateT subtype,
symbolS * symbol,
offsetT offset,
char *opcode);
char *frag_var (relax_stateT type,
int max_chars,
int var,
relax_substateT subtype,
symbolS * symbol,
offsetT offset,
char *opcode);
bfd_boolean frag_offset_fixed_p (const fragS *, const fragS *, offsetT *);
#endif /* FRAGS_H */

View File

@ -0,0 +1,597 @@
/* hash.c -- gas hash table code
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
2000, 2001, 2002, 2003, 2005, 2007, 2008, 2009, 2011, 2013
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* This version of the hash table code is a wholescale replacement of
the old hash table code, which was fairly bad. This is based on
the hash table code in BFD, but optimized slightly for the
assembler. The assembler does not need to derive structures that
are stored in the hash table. Instead, it always stores a pointer.
The assembler uses the hash table mostly to store symbols, and we
don't need to confuse the symbol structure with a hash table
structure. */
#include "as.h"
#include "safe-ctype.h"
#include "obstack.h"
/* An entry in a hash table. */
struct hash_entry {
/* Next entry for this hash code. */
struct hash_entry *next;
/* String being hashed. */
const char *string;
/* Hash code. This is the full hash code, not the index into the
table. */
unsigned long hash;
/* Pointer being stored in the hash table. */
void *data;
};
/* A hash table. */
struct hash_control {
/* The hash array. */
struct hash_entry **table;
/* The number of slots in the hash table. */
unsigned int size;
/* An obstack for this hash table. */
struct obstack memory;
#ifdef HASH_STATISTICS
/* Statistics. */
unsigned long lookups;
unsigned long hash_compares;
unsigned long string_compares;
unsigned long insertions;
unsigned long replacements;
unsigned long deletions;
#endif /* HASH_STATISTICS */
};
/* The default number of entries to use when creating a hash table.
Note this value can be reduced to 4051 by using the command line
switch --reduce-memory-overheads, or set to other values by using
the --hash-size=<NUMBER> switch. */
static unsigned long gas_hash_table_size = 65537;
void
set_gas_hash_table_size (unsigned long size)
{
gas_hash_table_size = bfd_hash_set_default_size (size);
}
/* Create a hash table. This return a control block. */
struct hash_control *
hash_new_sized (unsigned long size)
{
unsigned long alloc;
struct hash_control *ret;
ret = (struct hash_control *) xmalloc (sizeof *ret);
obstack_begin (&ret->memory, chunksize);
alloc = size * sizeof (struct hash_entry *);
ret->table = (struct hash_entry **) obstack_alloc (&ret->memory, alloc);
memset (ret->table, 0, alloc);
ret->size = size;
#ifdef HASH_STATISTICS
ret->lookups = 0;
ret->hash_compares = 0;
ret->string_compares = 0;
ret->insertions = 0;
ret->replacements = 0;
ret->deletions = 0;
#endif
return ret;
}
struct hash_control *
hash_new (void)
{
return hash_new_sized (gas_hash_table_size);
}
/* Delete a hash table, freeing all allocated memory. */
void
hash_die (struct hash_control *table)
{
obstack_free (&table->memory, 0);
free (table);
}
/* Look up a string in a hash table. This returns a pointer to the
hash_entry, or NULL if the string is not in the table. If PLIST is
not NULL, this sets *PLIST to point to the start of the list which
would hold this hash entry. If PHASH is not NULL, this sets *PHASH
to the hash code for KEY.
Each time we look up a string, we move it to the start of the list
for its hash code, to take advantage of referential locality. */
static struct hash_entry *
hash_lookup (struct hash_control *table, const char *key, size_t len,
struct hash_entry ***plist, unsigned long *phash)
{
unsigned long hash;
size_t n;
unsigned int c;
unsigned int hindex;
struct hash_entry **list;
struct hash_entry *p;
struct hash_entry *prev;
#ifdef HASH_STATISTICS
++table->lookups;
#endif
hash = 0;
for (n = 0; n < len; n++)
{
c = key[n];
hash += c + (c << 17);
hash ^= hash >> 2;
}
hash += len + (len << 17);
hash ^= hash >> 2;
if (phash != NULL)
*phash = hash;
hindex = hash % table->size;
list = table->table + hindex;
if (plist != NULL)
*plist = list;
prev = NULL;
for (p = *list; p != NULL; p = p->next)
{
#ifdef HASH_STATISTICS
++table->hash_compares;
#endif
if (p->hash == hash)
{
#ifdef HASH_STATISTICS
++table->string_compares;
#endif
if (strncmp (p->string, key, len) == 0 && p->string[len] == '\0')
{
if (prev != NULL)
{
prev->next = p->next;
p->next = *list;
*list = p;
}
return p;
}
}
prev = p;
}
return NULL;
}
/* Insert an entry into a hash table. This returns NULL on success.
On error, it returns a printable string indicating the error. It
is considered to be an error if the entry already exists in the
hash table. */
const char *
hash_insert (struct hash_control *table, const char *key, void *val)
{
struct hash_entry *p;
struct hash_entry **list;
unsigned long hash;
p = hash_lookup (table, key, strlen (key), &list, &hash);
if (p != NULL)
return "exists";
#ifdef HASH_STATISTICS
++table->insertions;
#endif
p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p));
p->string = key;
p->hash = hash;
p->data = val;
p->next = *list;
*list = p;
return NULL;
}
/* Insert or replace an entry in a hash table. This returns NULL on
success. On error, it returns a printable string indicating the
error. If an entry already exists, its value is replaced. */
const char *
hash_jam (struct hash_control *table, const char *key, void *val)
{
struct hash_entry *p;
struct hash_entry **list;
unsigned long hash;
p = hash_lookup (table, key, strlen (key), &list, &hash);
if (p != NULL)
{
#ifdef HASH_STATISTICS
++table->replacements;
#endif
p->data = val;
}
else
{
#ifdef HASH_STATISTICS
++table->insertions;
#endif
p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p));
p->string = key;
p->hash = hash;
p->data = val;
p->next = *list;
*list = p;
}
return NULL;
}
/* Replace an existing entry in a hash table. This returns the old
value stored for the entry. If the entry is not found in the hash
table, this does nothing and returns NULL. */
void *
hash_replace (struct hash_control *table, const char *key, void *value)
{
struct hash_entry *p;
void *ret;
p = hash_lookup (table, key, strlen (key), NULL, NULL);
if (p == NULL)
return NULL;
#ifdef HASH_STATISTICS
++table->replacements;
#endif
ret = p->data;
p->data = value;
return ret;
}
/* Find an entry in a hash table, returning its value. Returns NULL
if the entry is not found. */
void *
hash_find (struct hash_control *table, const char *key)
{
struct hash_entry *p;
p = hash_lookup (table, key, strlen (key), NULL, NULL);
if (p == NULL)
return NULL;
return p->data;
}
/* As hash_find, but KEY is of length LEN and is not guaranteed to be
NUL-terminated. */
void *
hash_find_n (struct hash_control *table, const char *key, size_t len)
{
struct hash_entry *p;
p = hash_lookup (table, key, len, NULL, NULL);
if (p == NULL)
return NULL;
return p->data;
}
/* Delete an entry from a hash table. This returns the value stored
for that entry, or NULL if there is no such entry. */
void *
hash_delete (struct hash_control *table, const char *key, int freeme)
{
struct hash_entry *p;
struct hash_entry **list;
p = hash_lookup (table, key, strlen (key), &list, NULL);
if (p == NULL)
return NULL;
if (p != *list)
abort ();
#ifdef HASH_STATISTICS
++table->deletions;
#endif
*list = p->next;
if (freeme)
obstack_free (&table->memory, p);
return p->data;
}
/* Traverse a hash table. Call the function on every entry in the
hash table. */
void
hash_traverse (struct hash_control *table,
void (*pfn) (const char *key, void *value))
{
unsigned int i;
for (i = 0; i < table->size; ++i)
{
struct hash_entry *p;
for (p = table->table[i]; p != NULL; p = p->next)
(*pfn) (p->string, p->data);
}
}
/* Print hash table statistics on the specified file. NAME is the
name of the hash table, used for printing a header. */
void
hash_print_statistics (FILE *f ATTRIBUTE_UNUSED,
const char *name ATTRIBUTE_UNUSED,
struct hash_control *table ATTRIBUTE_UNUSED)
{
#ifdef HASH_STATISTICS
unsigned int i;
unsigned long total;
unsigned long empty;
fprintf (f, "%s hash statistics:\n", name);
fprintf (f, "\t%lu lookups\n", table->lookups);
fprintf (f, "\t%lu hash comparisons\n", table->hash_compares);
fprintf (f, "\t%lu string comparisons\n", table->string_compares);
fprintf (f, "\t%lu insertions\n", table->insertions);
fprintf (f, "\t%lu replacements\n", table->replacements);
fprintf (f, "\t%lu deletions\n", table->deletions);
total = 0;
empty = 0;
for (i = 0; i < table->size; ++i)
{
struct hash_entry *p;
if (table->table[i] == NULL)
++empty;
else
{
for (p = table->table[i]; p != NULL; p = p->next)
++total;
}
}
fprintf (f, "\t%g average chain length\n", (double) total / table->size);
fprintf (f, "\t%lu empty slots\n", empty);
#endif
}
#ifdef TEST
/* This test program is left over from the old hash table code. */
/* Number of hash tables to maintain (at once) in any testing. */
#define TABLES (6)
/* We can have 12 statistics. */
#define STATBUFSIZE (12)
/* Display statistics here. */
int statbuf[STATBUFSIZE];
/* Human farts here. */
char answer[100];
/* We test many hash tables at once. */
char *hashtable[TABLES];
/* Points to current hash_control. */
char *h;
char **pp;
char *p;
char *name;
char *value;
int size;
int used;
char command;
/* Number 0:TABLES-1 of current hashed symbol table. */
int number;
int
main ()
{
void applicatee ();
void destroy ();
char *what ();
int *ip;
number = 0;
h = 0;
printf ("type h <RETURN> for help\n");
for (;;)
{
printf ("hash_test command: ");
gets (answer);
command = answer[0];
command = TOLOWER (command); /* Ecch! */
switch (command)
{
case '#':
printf ("old hash table #=%d.\n", number);
whattable ();
break;
case '?':
for (pp = hashtable; pp < hashtable + TABLES; pp++)
{
printf ("address of hash table #%d control block is %xx\n",
pp - hashtable, *pp);
}
break;
case 'a':
hash_traverse (h, applicatee);
break;
case 'd':
hash_traverse (h, destroy);
hash_die (h);
break;
case 'f':
p = hash_find (h, name = what ("symbol"));
printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT");
break;
case 'h':
printf ("# show old, select new default hash table number\n");
printf ("? display all hashtable control block addresses\n");
printf ("a apply a simple display-er to each symbol in table\n");
printf ("d die: destroy hashtable\n");
printf ("f find value of nominated symbol\n");
printf ("h this help\n");
printf ("i insert value into symbol\n");
printf ("j jam value into symbol\n");
printf ("n new hashtable\n");
printf ("r replace a value with another\n");
printf ("s say what %% of table is used\n");
printf ("q exit this program\n");
printf ("x delete a symbol from table, report its value\n");
break;
case 'i':
p = hash_insert (h, name = what ("symbol"), value = what ("value"));
if (p)
{
printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value,
p);
}
break;
case 'j':
p = hash_jam (h, name = what ("symbol"), value = what ("value"));
if (p)
{
printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p);
}
break;
case 'n':
h = hashtable[number] = (char *) hash_new ();
break;
case 'q':
exit (EXIT_SUCCESS);
case 'r':
p = hash_replace (h, name = what ("symbol"), value = what ("value"));
printf ("old value was \"%s\"\n", p ? p : "{}");
break;
case 's':
hash_say (h, statbuf, STATBUFSIZE);
for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++)
{
printf ("%d ", *ip);
}
printf ("\n");
break;
case 'x':
p = hash_delete (h, name = what ("symbol"));
printf ("old value was \"%s\"\n", p ? p : "{}");
break;
default:
printf ("I can't understand command \"%c\"\n", command);
break;
}
}
}
char *
what (description)
char *description;
{
printf (" %s : ", description);
gets (answer);
return xstrdup (answer);
}
void
destroy (string, value)
char *string;
char *value;
{
free (string);
free (value);
}
void
applicatee (string, value)
char *string;
char *value;
{
printf ("%.20s-%.20s\n", string, value);
}
/* Determine number: what hash table to use.
Also determine h: points to hash_control. */
void
whattable ()
{
for (;;)
{
printf (" what hash table (%d:%d) ? ", 0, TABLES - 1);
gets (answer);
sscanf (answer, "%d", &number);
if (number >= 0 && number < TABLES)
{
h = hashtable[number];
if (!h)
{
printf ("warning: current hash-table-#%d. has no hash-control\n", number);
}
return;
}
else
{
printf ("invalid hash table number: %d\n", number);
}
}
}
#endif /* TEST */

View File

@ -0,0 +1,89 @@
/* hash.h -- header file for gas hash table routines
Copyright 1987, 1992, 1993, 1995, 1999, 2003, 2005, 2007, 2008, 2013
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef HASH_H
#define HASH_H
struct hash_control;
/* Set the size of the hash table used. */
void set_gas_hash_table_size (unsigned long);
/* Create a hash table. This return a control block. */
extern struct hash_control *hash_new (void);
extern struct hash_control *hash_new_sized (unsigned long);
/* Delete a hash table, freeing all allocated memory. */
extern void hash_die (struct hash_control *);
/* Insert an entry into a hash table. This returns NULL on success.
On error, it returns a printable string indicating the error. It
is considered to be an error if the entry already exists in the
hash table. */
extern const char *hash_insert (struct hash_control *,
const char *key, void *value);
/* Insert or replace an entry in a hash table. This returns NULL on
success. On error, it returns a printable string indicating the
error. If an entry already exists, its value is replaced. */
extern const char *hash_jam (struct hash_control *,
const char *key, void *value);
/* Replace an existing entry in a hash table. This returns the old
value stored for the entry. If the entry is not found in the hash
table, this does nothing and returns NULL. */
extern void *hash_replace (struct hash_control *, const char *key,
void *value);
/* Find an entry in a hash table, returning its value. Returns NULL
if the entry is not found. */
extern void *hash_find (struct hash_control *, const char *key);
/* As hash_find, but KEY is of length LEN and is not guaranteed to be
NUL-terminated. */
extern void *hash_find_n (struct hash_control *, const char *key, size_t len);
/* Delete an entry from a hash table. This returns the value stored
for that entry, or NULL if there is no such entry. */
extern void *hash_delete (struct hash_control *, const char *key, int);
/* Traverse a hash table. Call the function on every entry in the
hash table. */
extern void hash_traverse (struct hash_control *,
void (*pfn) (const char *key, void *value));
/* Print hash table statistics on the specified file. NAME is the
name of the hash table, used for printing a header. */
extern void hash_print_statistics (FILE *, const char *name,
struct hash_control *);
#endif /* HASH_H */

View File

@ -0,0 +1,259 @@
/* input_file.c - Deal with Input Files -
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001,
2002, 2003, 2005, 2006, 2007, 2009, 2012
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* Confines all details of reading source bytes to this module.
All O/S specific crocks should live here.
What we lose in "efficiency" we gain in modularity.
Note we don't need to #include the "as.h" file. No common coupling! */
#include "as.h"
#include "input-file.h"
#include "safe-ctype.h"
/* This variable is non-zero if the file currently being read should be
preprocessed by app. It is zero if the file can be read straight in. */
int preprocess = 0;
/* This code opens a file, then delivers BUFFER_SIZE character
chunks of the file on demand.
BUFFER_SIZE is supposed to be a number chosen for speed.
The caller only asks once what BUFFER_SIZE is, and asks before
the nature of the input files (if any) is known. */
#define BUFFER_SIZE (32 * 1024)
/* We use static data: the data area is not sharable. */
static FILE *f_in;
static char *file_name;
/* Struct for saving the state of this module for file includes. */
struct saved_file
{
FILE * f_in;
char * file_name;
int preprocess;
char * app_save;
};
/* These hooks accommodate most operating systems. */
void
input_file_begin (void)
{
f_in = (FILE *) 0;
}
void
input_file_end (void)
{
}
/* Return BUFFER_SIZE. */
size_t
input_file_buffer_size (void)
{
return (BUFFER_SIZE);
}
/* Push the state of our input, returning a pointer to saved info that
can be restored with input_file_pop (). */
char *
input_file_push (void)
{
register struct saved_file *saved;
saved = (struct saved_file *) xmalloc (sizeof *saved);
saved->f_in = f_in;
saved->file_name = file_name;
saved->preprocess = preprocess;
if (preprocess)
saved->app_save = app_push ();
/* Initialize for new file. */
input_file_begin ();
return (char *) saved;
}
void
input_file_pop (char *arg)
{
register struct saved_file *saved = (struct saved_file *) arg;
input_file_end (); /* Close out old file. */
f_in = saved->f_in;
file_name = saved->file_name;
preprocess = saved->preprocess;
if (preprocess)
app_pop (saved->app_save);
free (arg);
}
void
input_file_open (char *filename, /* "" means use stdin. Must not be 0. */
int pre)
{
int c;
char buf[80];
preprocess = pre;
gas_assert (filename != 0); /* Filename may not be NULL. */
if (filename[0])
{
f_in = fopen (filename, FOPEN_RT);
file_name = filename;
}
else
{
/* Use stdin for the input file. */
f_in = stdin;
/* For error messages. */
file_name = _("{standard input}");
}
if (f_in == NULL)
{
as_bad (_("can't open %s for reading: %s"),
file_name, xstrerror (errno));
return;
}
c = getc (f_in);
if (ferror (f_in))
{
as_bad (_("can't read from %s: %s"),
file_name, xstrerror (errno));
fclose (f_in);
f_in = NULL;
return;
}
/* Check for an empty input file. */
if (feof (f_in))
{
fclose (f_in);
f_in = NULL;
return;
}
gas_assert (c != EOF);
if (c == '#')
{
/* Begins with comment, may not want to preprocess. */
c = getc (f_in);
if (c == 'N')
{
if (fgets (buf, sizeof (buf), f_in)
&& !strncmp (buf, "O_APP", 5) && ISSPACE (buf[5]))
preprocess = 0;
if (!strchr (buf, '\n'))
ungetc ('#', f_in); /* It was longer. */
else
ungetc ('\n', f_in);
}
else if (c == 'A')
{
if (fgets (buf, sizeof (buf), f_in)
&& !strncmp (buf, "PP", 2) && ISSPACE (buf[2]))
preprocess = 1;
if (!strchr (buf, '\n'))
ungetc ('#', f_in);
else
ungetc ('\n', f_in);
}
else if (c == '\n')
ungetc ('\n', f_in);
else
ungetc ('#', f_in);
}
else
ungetc (c, f_in);
}
/* Close input file. */
void
input_file_close (void)
{
/* Don't close a null file pointer. */
if (f_in != NULL)
fclose (f_in);
f_in = 0;
}
/* This function is passed to do_scrub_chars. */
static size_t
input_file_get (char *buf, size_t buflen)
{
size_t size;
if (feof (f_in))
return 0;
size = fread (buf, sizeof (char), buflen, f_in);
if (ferror (f_in))
as_bad (_("can't read from %s: %s"), file_name, xstrerror (errno));
return size;
}
/* Read a buffer from the input file. */
char *
input_file_give_next_buffer (char *where /* Where to place 1st character of new buffer. */)
{
char *return_value; /* -> Last char of what we read, + 1. */
size_t size;
if (f_in == (FILE *) 0)
return 0;
/* fflush (stdin); could be done here if you want to synchronise
stdin and stdout, for the case where our input file is stdin.
Since the assembler shouldn't do any output to stdout, we
don't bother to synch output and input. */
if (preprocess)
size = do_scrub_chars (input_file_get, where, BUFFER_SIZE);
else
size = input_file_get (where, BUFFER_SIZE);
if (size)
return_value = where + size;
else
{
if (fclose (f_in))
as_warn (_("can't close %s: %s"), file_name, xstrerror (errno));
f_in = (FILE *) 0;
return_value = 0;
}
return return_value;
}

View File

@ -0,0 +1,66 @@
/* input_file.h header for input-file.c
Copyright 1987, 1992, 1993, 2000, 2003, 2005, 2006, 2007, 2012
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/*"input_file.c":Operating-system dependant functions to read source files.*/
/*
* No matter what the operating system, this module must provide the
* following services to its callers.
*
* input_file_begin() Call once before anything else.
*
* input_file_end() Call once after everything else.
*
* input_file_buffer_size() Call anytime. Returns largest possible
* delivery from
* input_file_give_next_buffer().
*
* input_file_open(name) Call once for each input file.
*
* input_file_give_next_buffer(where) Call once to get each new buffer.
* Return 0: no more chars left in file,
* the file has already been closed.
* Otherwise: return a pointer to just
* after the last character we read
* into the buffer.
* If we can only read 0 characters, then
* end-of-file is faked.
*
* input_file_push() Push state, which can be restored
* later. Does implicit input_file_begin.
* Returns char * to saved state.
*
* input_file_pop (arg) Pops previously saved state.
*
* input_file_close () Closes opened file.
*
* All errors are reported so caller doesn't have to think
* about I/O errors.
*/
char *input_file_give_next_buffer (char *where);
char *input_file_push (void);
size_t input_file_buffer_size (void);
void input_file_begin (void);
void input_file_close (void);
void input_file_end (void);
void input_file_open (char *filename, int pre);
void input_file_pop (char *arg);

View File

@ -0,0 +1,523 @@
/* input_scrub.c - Break up input buffers into whole numbers of lines.
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
2000, 2001, 2003, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "filenames.h"
#include "input-file.h"
#include "sb.h"
#include "listing.h"
/*
* O/S independent module to supply buffers of sanitised source code
* to rest of assembler. We get sanitised input data of arbitrary length.
* We break these buffers on line boundaries, recombine pieces that
* were broken across buffers, and return a buffer of full lines to
* the caller.
* The last partial line begins the next buffer we build and return to caller.
* The buffer returned to caller is preceded by BEFORE_STRING and followed
* by AFTER_STRING, as sentinels. The last character before AFTER_STRING
* is a newline.
* Also looks after line numbers, for e.g. error messages.
*/
/*
* We don't care how filthy our buffers are, but our callers assume
* that the following sanitation has already been done.
*
* No comments, reduce a comment to a space.
* Reduce a tab to a space unless it is 1st char of line.
* All multiple tabs and spaces collapsed into 1 char. Tab only
* legal if 1st char of line.
* # line file statements converted to .line x;.file y; statements.
* Escaped newlines at end of line: remove them but add as many newlines
* to end of statement as you removed in the middle, to synch line numbers.
*/
#define BEFORE_STRING ("\n")
#define AFTER_STRING ("\0") /* memcpy of 0 chars might choke. */
#define BEFORE_SIZE (1)
#define AFTER_SIZE (1)
#ifndef TC_EOL_IN_INSN
#define TC_EOL_IN_INSN(P) 0
#endif
static char *buffer_start; /*->1st char of full buffer area. */
static char *partial_where; /*->after last full line in buffer. */
static int partial_size; /* >=0. Number of chars in partial line in buffer. */
/* Because we need AFTER_STRING just after last full line, it clobbers
1st part of partial line. So we preserve 1st part of partial line
here. */
static char save_source[AFTER_SIZE];
/* What is the largest size buffer that input_file_give_next_buffer()
could return to us? */
static unsigned int buffer_length;
/* The index into an sb structure we are reading from. -1 if none. */
static size_t sb_index = -1;
/* If we are reading from an sb structure, this is it. */
static sb from_sb;
/* Should we do a conditional check on from_sb? */
static int from_sb_is_expansion = 1;
/* The number of nested sb structures we have included. */
int macro_nest;
/* We can have more than one source file open at once, though the info for all
but the latest one are saved off in a struct input_save. These files remain
open, so we are limited by the number of open files allowed by the
underlying OS. We may also sequentially read more than one source file in an
assembly. */
/* We must track the physical file and line number for error messages. We also
track a "logical" file and line number corresponding to (C?) compiler
source line numbers. Whenever we open a file we must fill in
physical_input_file. So if it is NULL we have not opened any files yet. */
static char *physical_input_file;
static char *logical_input_file;
/* 1-origin line number in a source file. */
/* A line ends in '\n' or eof. */
static unsigned int physical_input_line;
static int logical_input_line;
/* Struct used to save the state of the input handler during include files */
struct input_save {
char * buffer_start;
char * partial_where;
int partial_size;
char save_source[AFTER_SIZE];
size_t buffer_length;
char * physical_input_file;
char * logical_input_file;
unsigned int physical_input_line;
int logical_input_line;
size_t sb_index;
sb from_sb;
int from_sb_is_expansion; /* Should we do a conditional check? */
struct input_save * next_saved_file; /* Chain of input_saves. */
char * input_file_save; /* Saved state of input routines. */
char * saved_position; /* Caller's saved position in buf. */
};
static struct input_save *input_scrub_push (char *saved_position);
static char *input_scrub_pop (struct input_save *arg);
/* Saved information about the file that .include'd this one. When we hit EOF,
we automatically pop to that file. */
static struct input_save *next_saved_file;
/* Push the state of input reading and scrubbing so that we can #include.
The return value is a 'void *' (fudged for old compilers) to a save
area, which can be restored by passing it to input_scrub_pop(). */
static struct input_save *
input_scrub_push (char *saved_position)
{
register struct input_save *saved;
saved = (struct input_save *) xmalloc (sizeof *saved);
saved->saved_position = saved_position;
saved->buffer_start = buffer_start;
saved->partial_where = partial_where;
saved->partial_size = partial_size;
saved->buffer_length = buffer_length;
saved->physical_input_file = physical_input_file;
saved->logical_input_file = logical_input_file;
saved->physical_input_line = physical_input_line;
saved->logical_input_line = logical_input_line;
saved->sb_index = sb_index;
saved->from_sb = from_sb;
saved->from_sb_is_expansion = from_sb_is_expansion;
memcpy (saved->save_source, save_source, sizeof (save_source));
saved->next_saved_file = next_saved_file;
saved->input_file_save = input_file_push ();
input_file_begin (); /* Reinitialize! */
logical_input_line = -1;
logical_input_file = (char *) NULL;
buffer_length = input_file_buffer_size ();
sb_index = -1;
buffer_start = (char *) xmalloc ((BEFORE_SIZE + buffer_length
+ buffer_length + AFTER_SIZE));
memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE);
return saved;
}
static char *
input_scrub_pop (struct input_save *saved)
{
char *saved_position;
input_scrub_end (); /* Finish off old buffer */
input_file_pop (saved->input_file_save);
saved_position = saved->saved_position;
buffer_start = saved->buffer_start;
buffer_length = saved->buffer_length;
physical_input_file = saved->physical_input_file;
logical_input_file = saved->logical_input_file;
physical_input_line = saved->physical_input_line;
logical_input_line = saved->logical_input_line;
sb_index = saved->sb_index;
from_sb = saved->from_sb;
from_sb_is_expansion = saved->from_sb_is_expansion;
partial_where = saved->partial_where;
partial_size = saved->partial_size;
next_saved_file = saved->next_saved_file;
memcpy (save_source, saved->save_source, sizeof (save_source));
free (saved);
return saved_position;
}
void
input_scrub_begin (void)
{
know (strlen (BEFORE_STRING) == BEFORE_SIZE);
know (strlen (AFTER_STRING) == AFTER_SIZE
|| (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1));
input_file_begin ();
buffer_length = input_file_buffer_size ();
buffer_start = (char *) xmalloc ((BEFORE_SIZE + buffer_length
+ buffer_length + AFTER_SIZE));
memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE);
/* Line number things. */
logical_input_line = -1;
logical_input_file = (char *) NULL;
physical_input_file = NULL; /* No file read yet. */
next_saved_file = NULL; /* At EOF, don't pop to any other file */
do_scrub_begin (flag_m68k_mri);
}
void
input_scrub_end (void)
{
if (buffer_start)
{
free (buffer_start);
buffer_start = 0;
input_file_end ();
}
}
/* Start reading input from a new file.
Return start of caller's part of buffer. */
char *
input_scrub_new_file (char *filename)
{
input_file_open (filename, !flag_no_comments);
physical_input_file = filename[0] ? filename : _("{standard input}");
physical_input_line = 0;
partial_size = 0;
return (buffer_start + BEFORE_SIZE);
}
/* Include a file from the current file. Save our state, cause it to
be restored on EOF, and begin handling a new file. Same result as
input_scrub_new_file. */
char *
input_scrub_include_file (char *filename, char *position)
{
next_saved_file = input_scrub_push (position);
return input_scrub_new_file (filename);
}
/* Start getting input from an sb structure. This is used when
expanding a macro. */
void
input_scrub_include_sb (sb *from, char *position, int is_expansion)
{
int newline;
if (macro_nest > max_macro_nest)
as_fatal (_("macros nested too deeply"));
++macro_nest;
#ifdef md_macro_start
if (is_expansion)
{
md_macro_start ();
}
#endif
next_saved_file = input_scrub_push (position);
/* Allocate sufficient space: from->len + optional newline. */
newline = from->len >= 1 && from->ptr[0] != '\n';
sb_build (&from_sb, from->len + newline);
from_sb_is_expansion = is_expansion;
if (newline)
{
/* Add the sentinel required by read.c. */
sb_add_char (&from_sb, '\n');
}
sb_scrub_and_add_sb (&from_sb, from);
/* Make sure the parser looks at defined contents when it scans for
e.g. end-of-line at the end of a macro. */
sb_terminate (&from_sb);
sb_index = 1;
/* These variables are reset by input_scrub_push. Restore them
since we are, after all, still at the same point in the file. */
logical_input_line = next_saved_file->logical_input_line;
logical_input_file = next_saved_file->logical_input_file;
}
void
input_scrub_close (void)
{
input_file_close ();
physical_input_line = 0;
logical_input_line = -1;
}
char *
input_scrub_next_buffer (char **bufp)
{
register char *limit; /*->just after last char of buffer. */
if (sb_index != (size_t) -1)
{
if (sb_index >= from_sb.len)
{
sb_kill (&from_sb);
if (from_sb_is_expansion)
{
cond_finish_check (macro_nest);
#ifdef md_macro_end
/* Allow the target to clean up per-macro expansion
data. */
md_macro_end ();
#endif
}
--macro_nest;
partial_where = NULL;
if (next_saved_file != NULL)
*bufp = input_scrub_pop (next_saved_file);
return partial_where;
}
partial_where = from_sb.ptr + from_sb.len;
partial_size = 0;
*bufp = from_sb.ptr + sb_index;
sb_index = from_sb.len;
return partial_where;
}
*bufp = buffer_start + BEFORE_SIZE;
if (partial_size)
{
memmove (buffer_start + BEFORE_SIZE, partial_where,
(unsigned int) partial_size);
memcpy (buffer_start + BEFORE_SIZE, save_source, AFTER_SIZE);
}
limit = input_file_give_next_buffer (buffer_start
+ BEFORE_SIZE
+ partial_size);
if (limit)
{
register char *p; /* Find last newline. */
/* Terminate the buffer to avoid confusing TC_EOL_IN_INSN. */
*limit = '\0';
for (p = limit - 1; *p != '\n' || TC_EOL_IN_INSN (p); --p)
;
++p;
while (p <= buffer_start + BEFORE_SIZE)
{
int limoff;
limoff = limit - buffer_start;
buffer_length += input_file_buffer_size ();
buffer_start = (char *) xrealloc (buffer_start,
(BEFORE_SIZE
+ 2 * buffer_length
+ AFTER_SIZE));
*bufp = buffer_start + BEFORE_SIZE;
limit = input_file_give_next_buffer (buffer_start + limoff);
if (limit == NULL)
{
as_warn (_("partial line at end of file ignored"));
partial_where = NULL;
if (next_saved_file)
*bufp = input_scrub_pop (next_saved_file);
return NULL;
}
/* Terminate the buffer to avoid confusing TC_EOL_IN_INSN. */
*limit = '\0';
for (p = limit - 1; *p != '\n' || TC_EOL_IN_INSN (p); --p)
;
++p;
}
partial_where = p;
partial_size = limit - p;
memcpy (save_source, partial_where, (int) AFTER_SIZE);
memcpy (partial_where, AFTER_STRING, (int) AFTER_SIZE);
}
else
{
partial_where = 0;
if (partial_size > 0)
{
as_warn (_("partial line at end of file ignored"));
}
/* Tell the listing we've finished the file. */
LISTING_EOF ();
/* If we should pop to another file at EOF, do it. */
if (next_saved_file)
{
*bufp = input_scrub_pop (next_saved_file); /* Pop state */
/* partial_where is now correct to return, since we popped it. */
}
}
return (partial_where);
}
/* The remaining part of this file deals with line numbers, error
messages and so on. Return TRUE if we opened any file. */
int
seen_at_least_1_file (void)
{
return (physical_input_file != NULL);
}
void
bump_line_counters (void)
{
if (sb_index == (size_t) -1)
{
++physical_input_line;
if (logical_input_line >= 0)
++logical_input_line;
}
}
/* Tells us what the new logical line number and file are.
If the line_number is -1, we don't change the current logical line
number. If it is -2, we decrement the logical line number (this is
to support the .appfile pseudo-op inserted into the stream by
do_scrub_chars).
If the fname is NULL, we don't change the current logical file name.
Returns nonzero if the filename actually changes. */
int
new_logical_line_flags (char *fname, /* DON'T destroy it! We point to it! */
int line_number,
int flags)
{
switch (flags)
{
case 0:
break;
case 1:
if (line_number != -1)
abort ();
break;
case 1 << 1:
case 1 << 2:
/* FIXME: we could check that include nesting is correct. */
break;
default:
abort ();
}
if (line_number >= 0)
logical_input_line = line_number;
else if (line_number == -1 && fname && !*fname && (flags & (1 << 2)))
{
logical_input_file = physical_input_file;
logical_input_line = physical_input_line;
fname = NULL;
}
if (fname
&& (logical_input_file == NULL
|| filename_cmp (logical_input_file, fname)))
{
logical_input_file = fname;
return 1;
}
else
return 0;
}
int
new_logical_line (char *fname, int line_number)
{
return new_logical_line_flags (fname, line_number, 0);
}
/* Return the current file name and line number.
namep should be char * const *, but there are compilers which screw
up declarations like that, and it's easier to avoid it. */
void
as_where (char **namep, unsigned int *linep)
{
if (logical_input_file != NULL
&& (linep == NULL || logical_input_line >= 0))
{
*namep = logical_input_file;
if (linep != NULL)
*linep = logical_input_line;
}
else if (physical_input_file != NULL)
{
*namep = physical_input_file;
if (linep != NULL)
*linep = physical_input_line;
}
else
{
*namep = 0;
if (linep != NULL)
*linep = 0;
}
}

View File

@ -0,0 +1 @@
#include "itbl-i386.h"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
/* This file is listing.h
Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1995, 1997, 1998,
2003, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef __listing_h__
#define __listing_h__
#define LISTING_LISTING 1
#define LISTING_SYMBOLS 2
#define LISTING_NOFORM 4
#define LISTING_HLL 8
#define LISTING_NODEBUG 16
#define LISTING_NOCOND 32
#define LISTING_MACEXP 64
#define LISTING_GENERAL 128
#define LISTING_DEFAULT (LISTING_LISTING | LISTING_HLL | LISTING_SYMBOLS)
#ifndef NO_LISTING
#define LISTING_NEWLINE() { if (listing) listing_newline (NULL); }
#else
#define LISTING_NEWLINE() {;}
#endif
#define LISTING_EOF() LISTING_NEWLINE()
#define LISTING_SKIP_COND() ((listing & LISTING_NOCOND) != 0)
void listing_eject (int);
void listing_error (const char *message);
void listing_file (const char *name);
void listing_list (int on);
void listing_newline (char *ps);
void listing_prev_line (void);
void listing_print (char *, char **);
void listing_psize (int);
void listing_nopage (int);
void listing_source_file (const char *);
void listing_source_line (unsigned int);
void listing_title (int depth);
void listing_warning (const char *message);
void listing_width (unsigned int x);
extern int listing_lhs_width;
extern int listing_lhs_width_second;
extern int listing_lhs_cont_lines;
extern int listing_rhs_width;
#endif /* __listing_h__ */
/* end of listing.h */

View File

@ -0,0 +1,96 @@
/* literal.c - GAS literal pool management.
Copyright 1994, 2000, 2005, 2007 Free Software Foundation, Inc.
Written by Ken Raeburn (raeburn@cygnus.com).
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* This isn't quite a "constant" pool. Some of the values may get
adjusted at run time, e.g., for symbolic relocations when shared
libraries are in use. It's more of a "literal" pool.
On the Alpha, this should be used for .lita and .lit8. (Is there
ever a .lit4?) On the MIPS, it could be used for .lit4 as well.
The expressions passed here should contain either constants or symbols,
not a combination of both. Typically, the constant pool is accessed
with some sort of GP register, so the size of the pool must be kept down
if possible. The exception is section offsets -- if you're storing a
pointer to the start of .data, for example, and your machine provides
for 16-bit signed addends, you might want to store .data+32K, so that
you can access all of the first 64K of .data with the one pointer.
This isn't a requirement, just a guideline that can help keep .o file
size down. */
#include "as.h"
#include "subsegs.h"
#ifdef NEED_LITERAL_POOL
valueT
add_to_literal_pool (sym, addend, sec, size)
symbolS *sym;
valueT addend;
segT sec;
int size;
{
segT current_section = now_seg;
int current_subsec = now_subseg;
valueT offset;
bfd_reloc_code_real_type reloc_type;
char *p;
segment_info_type *seginfo = seg_info (sec);
fixS *fixp;
offset = 0;
/* @@ This assumes all entries in a given section will be of the same
size... Probably correct, but unwise to rely on. */
/* This must always be called with the same subsegment. */
if (seginfo->frchainP)
for (fixp = seginfo->frchainP->fix_root;
fixp != (fixS *) NULL;
fixp = fixp->fx_next, offset += size)
{
if (fixp->fx_addsy == sym && fixp->fx_offset == addend)
return offset;
}
subseg_set (sec, 0);
p = frag_more (size);
memset (p, 0, size);
switch (size)
{
case 4:
reloc_type = BFD_RELOC_32;
break;
case 8:
reloc_type = BFD_RELOC_64;
break;
default:
abort ();
}
fix_new (frag_now, p - frag_now->fr_literal, size, sym, addend, 0,
reloc_type);
subseg_set (current_section, current_subsec);
offset = seginfo->literal_pool_size;
seginfo->literal_pool_size += size;
return offset;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,97 @@
/* macro.h - header file for macro support for gas
Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2006,
2007, 2012 Free Software Foundation, Inc.
Written by Steve and Judy Chamberlain of Cygnus Support,
sac@cygnus.com
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef MACRO_H
#define MACRO_H
/* Structures used to store macros.
Each macro knows its name and included text. It gets built with a
list of formal arguments, and also keeps a hash table which points
into the list to speed up formal search. Each formal knows its
name and its default value. Each time the macro is expanded, the
formals get the actual values attached to them. */
enum formal_type
{
FORMAL_OPTIONAL,
FORMAL_REQUIRED,
FORMAL_VARARG
};
/* Describe the formal arguments to a macro. */
typedef struct formal_struct {
struct formal_struct *next; /* Next formal in list. */
sb name; /* Name of the formal. */
sb def; /* The default value. */
sb actual; /* The actual argument (changed on each expansion). */
int index; /* The index of the formal 0..formal_count - 1. */
enum formal_type type; /* The kind of the formal. */
} formal_entry;
/* Other values found in the index field of a formal_entry. */
#define QUAL_INDEX (-1)
#define NARG_INDEX (-2)
#define LOCAL_INDEX (-3)
/* Describe the macro. */
typedef struct macro_struct
{
sb sub; /* Substitution text. */
int formal_count; /* Number of formal args. */
formal_entry *formals; /* Pointer to list of formal_structs. */
struct hash_control *formal_hash; /* Hash table of formals. */
const char *name; /* Macro name. */
char *file; /* File the macro was defined in. */
unsigned int line; /* Line number of definition. */
} macro_entry;
/* Whether any macros have been defined. */
extern int macro_defined;
/* The macro nesting level. */
extern int macro_nest;
/* The macro hash table. */
extern struct hash_control *macro_hash;
extern int buffer_and_nest (const char *, const char *, sb *,
size_t (*) (sb *));
extern void macro_init (int, int, int,
size_t (*) (const char *, size_t, sb *, offsetT *));
extern void macro_set_alternate (int);
extern void macro_mri_mode (int);
extern const char *define_macro (size_t, sb *, sb *, size_t (*) (sb *),
char *, unsigned int, const char **);
extern int check_macro (const char *, sb *, const char **, macro_entry **);
extern void delete_macro (const char *);
extern const char *expand_irp (int, size_t, sb *, sb *, size_t (*) (sb *));
#endif

View File

@ -0,0 +1,440 @@
/* messages.c - error reporter -
Copyright 1987, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
static void identify (char *);
static void as_show_where (void);
static void as_warn_internal (char *, unsigned int, char *);
static void as_bad_internal (char *, unsigned int, char *);
/* Despite the rest of the comments in this file, (FIXME-SOON),
here is the current scheme for error messages etc:
as_fatal() is used when gas is quite confused and
continuing the assembly is pointless. In this case we
exit immediately with error status.
as_bad() is used to mark errors that result in what we
presume to be a useless object file. Say, we ignored
something that might have been vital. If we see any of
these, assembly will continue to the end of the source,
no object file will be produced, and we will terminate
with error status. The new option, -Z, tells us to
produce an object file anyway but we still exit with
error status. The assumption here is that you don't want
this object file but we could be wrong.
as_warn() is used when we have an error from which we
have a plausible error recovery. eg, masking the top
bits of a constant that is longer than will fit in the
destination. In this case we will continue to assemble
the source, although we may have made a bad assumption,
and we will produce an object file and return normal exit
status (ie, no error). The new option -X tells us to
treat all as_warn() errors as as_bad() errors. That is,
no object file will be produced and we will exit with
error status. The idea here is that we don't kill an
entire make because of an error that we knew how to
correct. On the other hand, sometimes you might want to
stop the make at these points.
as_tsktsk() is used when we see a minor error for which
our error recovery action is almost certainly correct.
In this case, we print a message and then assembly
continues as though no error occurred. */
static void
identify (char *file)
{
static int identified;
if (identified)
return;
identified++;
if (!file)
{
unsigned int x;
as_where (&file, &x);
}
if (file)
fprintf (stderr, "%s: ", file);
fprintf (stderr, _("Assembler messages:\n"));
}
/* The number of warnings issued. */
static int warning_count;
int
had_warnings (void)
{
return warning_count;
}
/* Nonzero if we've hit a 'bad error', and should not write an obj file,
and exit with a nonzero error code. */
static int error_count;
int
had_errors (void)
{
return error_count;
}
/* Print the current location to stderr. */
static void
as_show_where (void)
{
char *file;
unsigned int line;
as_where (&file, &line);
identify (file);
if (file)
{
if (line != 0)
fprintf (stderr, "%s:%u: ", file, line);
else
fprintf (stderr, "%s: ", file);
}
}
/* Send to stderr a string as a warning, and locate warning
in input file(s).
Please only use this for when we have some recovery action.
Please explain in string (which may have '\n's) what recovery was
done. */
void
as_tsktsk (const char *format, ...)
{
va_list args;
as_show_where ();
va_start (args, format);
vfprintf (stderr, format, args);
va_end (args);
(void) putc ('\n', stderr);
}
/* The common portion of as_warn and as_warn_where. */
static void
as_warn_internal (char *file, unsigned int line, char *buffer)
{
++warning_count;
if (file == NULL)
as_where (&file, &line);
identify (file);
if (file)
{
if (line != 0)
fprintf (stderr, "%s:%u: ", file, line);
else
fprintf (stderr, "%s: ", file);
}
fprintf (stderr, _("Warning: "));
fputs (buffer, stderr);
(void) putc ('\n', stderr);
#ifndef NO_LISTING
listing_warning (buffer);
#endif
}
/* Send to stderr a string as a warning, and locate warning
in input file(s).
Please only use this for when we have some recovery action.
Please explain in string (which may have '\n's) what recovery was
done. */
void
as_warn (const char *format, ...)
{
va_list args;
char buffer[2000];
if (!flag_no_warnings)
{
va_start (args, format);
vsnprintf (buffer, sizeof (buffer), format, args);
va_end (args);
as_warn_internal ((char *) NULL, 0, buffer);
}
}
/* Like as_bad but the file name and line number are passed in.
Unfortunately, we have to repeat the function in order to handle
the varargs correctly and portably. */
void
as_warn_where (char *file, unsigned int line, const char *format, ...)
{
va_list args;
char buffer[2000];
if (!flag_no_warnings)
{
va_start (args, format);
vsnprintf (buffer, sizeof (buffer), format, args);
va_end (args);
as_warn_internal (file, line, buffer);
}
}
/* The common portion of as_bad and as_bad_where. */
static void
as_bad_internal (char *file, unsigned int line, char *buffer)
{
++error_count;
if (file == NULL)
as_where (&file, &line);
identify (file);
if (file)
{
if (line != 0)
fprintf (stderr, "%s:%u: ", file, line);
else
fprintf (stderr, "%s: ", file);
}
fprintf (stderr, _("Error: "));
fputs (buffer, stderr);
(void) putc ('\n', stderr);
#ifndef NO_LISTING
listing_error (buffer);
#endif
}
/* Send to stderr a string as a warning, and locate warning in input
file(s). Please us when there is no recovery, but we want to
continue processing but not produce an object file.
Please explain in string (which may have '\n's) what recovery was
done. */
void
as_bad (const char *format, ...)
{
va_list args;
char buffer[2000];
va_start (args, format);
vsnprintf (buffer, sizeof (buffer), format, args);
va_end (args);
as_bad_internal ((char *) NULL, 0, buffer);
}
/* Like as_bad but the file name and line number are passed in.
Unfortunately, we have to repeat the function in order to handle
the varargs correctly and portably. */
void
as_bad_where (char *file, unsigned int line, const char *format, ...)
{
va_list args;
char buffer[2000];
va_start (args, format);
vsnprintf (buffer, sizeof (buffer), format, args);
va_end (args);
as_bad_internal (file, line, buffer);
}
/* Send to stderr a string as a fatal message, and print location of
error in input file(s).
Please only use this for when we DON'T have some recovery action.
It xexit()s with a warning status. */
void
as_fatal (const char *format, ...)
{
va_list args;
as_show_where ();
va_start (args, format);
fprintf (stderr, _("Fatal error: "));
vfprintf (stderr, format, args);
(void) putc ('\n', stderr);
va_end (args);
/* Delete the output file, if it exists. This will prevent make from
thinking that a file was created and hence does not need rebuilding. */
if (out_file_name != NULL)
unlink_if_ordinary (out_file_name);
xexit (EXIT_FAILURE);
}
/* Indicate assertion failure.
Arguments: Filename, line number, optional function name. */
void
as_assert (const char *file, int line, const char *fn)
{
as_show_where ();
fprintf (stderr, _("Internal error!\n"));
if (fn)
fprintf (stderr, _("Assertion failure in %s at %s line %d.\n"),
fn, file, line);
else
fprintf (stderr, _("Assertion failure at %s line %d.\n"), file, line);
fprintf (stderr, _("Please report this bug.\n"));
xexit (EXIT_FAILURE);
}
/* as_abort: Print a friendly message saying how totally hosed we are,
and exit without producing a core file. */
void
as_abort (const char *file, int line, const char *fn)
{
as_show_where ();
if (fn)
fprintf (stderr, _("Internal error, aborting at %s line %d in %s\n"),
file, line, fn);
else
fprintf (stderr, _("Internal error, aborting at %s line %d\n"),
file, line);
fprintf (stderr, _("Please report this bug.\n"));
xexit (EXIT_FAILURE);
}
/* Support routines. */
void
sprint_value (char *buf, valueT val)
{
if (sizeof (val) <= sizeof (long))
{
sprintf (buf, "%ld", (long) val);
return;
}
if (sizeof (val) <= sizeof (bfd_vma))
{
sprintf_vma (buf, val);
return;
}
abort ();
}
#define HEX_MAX_THRESHOLD 1024
#define HEX_MIN_THRESHOLD -(HEX_MAX_THRESHOLD)
static void
as_internal_value_out_of_range (char * prefix,
offsetT val,
offsetT min,
offsetT max,
char * file,
unsigned line,
int bad)
{
const char * err;
if (prefix == NULL)
prefix = "";
if (val >= min && val <= max)
{
addressT right = max & -max;
if (max <= 1)
abort ();
/* xgettext:c-format */
err = _("%s out of domain (%d is not a multiple of %d)");
if (bad)
as_bad_where (file, line, err,
prefix, (int) val, (int) right);
else
as_warn_where (file, line, err,
prefix, (int) val, (int) right);
return;
}
if ( val < HEX_MAX_THRESHOLD
&& min < HEX_MAX_THRESHOLD
&& max < HEX_MAX_THRESHOLD
&& val > HEX_MIN_THRESHOLD
&& min > HEX_MIN_THRESHOLD
&& max > HEX_MIN_THRESHOLD)
{
/* xgettext:c-format */
err = _("%s out of range (%d is not between %d and %d)");
if (bad)
as_bad_where (file, line, err,
prefix, (int) val, (int) min, (int) max);
else
as_warn_where (file, line, err,
prefix, (int) val, (int) min, (int) max);
}
else
{
char val_buf [sizeof (val) * 3 + 2];
char min_buf [sizeof (val) * 3 + 2];
char max_buf [sizeof (val) * 3 + 2];
if (sizeof (val) > sizeof (bfd_vma))
abort ();
sprintf_vma (val_buf, (bfd_vma) val);
sprintf_vma (min_buf, (bfd_vma) min);
sprintf_vma (max_buf, (bfd_vma) max);
/* xgettext:c-format. */
err = _("%s out of range (0x%s is not between 0x%s and 0x%s)");
if (bad)
as_bad_where (file, line, err, prefix, val_buf, min_buf, max_buf);
else
as_warn_where (file, line, err, prefix, val_buf, min_buf, max_buf);
}
}
void
as_warn_value_out_of_range (char * prefix,
offsetT value,
offsetT min,
offsetT max,
char * file,
unsigned line)
{
as_internal_value_out_of_range (prefix, value, min, max, file, line, 0);
}
void
as_bad_value_out_of_range (char * prefix,
offsetT value,
offsetT min,
offsetT max,
char * file,
unsigned line)
{
as_internal_value_out_of_range (prefix, value, min, max, file, line, 1);
}

View File

@ -0,0 +1 @@
#include "obj-coff.h"

View File

@ -0,0 +1,87 @@
/* obj.h - defines the object dependent hooks for all object
format backends.
Copyright 1987, 1990, 1991, 1992, 1993, 1995, 1996, 1997, 1999, 2000,
2002, 2003, 2004, 2005, 2007, 2009, 2010 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
char *obj_default_output_file_name (void);
void obj_emit_relocations (char **where, fixS * fixP,
relax_addressT segment_address_in_file);
void obj_emit_strings (char **where);
void obj_emit_symbols (char **where, symbolS * symbols);
#ifndef obj_read_begin_hook
void obj_read_begin_hook (void);
#endif
#ifndef obj_symbol_new_hook
void obj_symbol_new_hook (symbolS * symbolP);
#endif
void obj_symbol_to_chars (char **where, symbolS * symbolP);
extern const pseudo_typeS obj_pseudo_table[];
struct format_ops {
int flavor;
unsigned dfl_leading_underscore : 1;
unsigned emit_section_symbols : 1;
void (*begin) (void);
void (*app_file) (const char *, int);
void (*frob_symbol) (symbolS *, int *);
void (*frob_file) (void);
void (*frob_file_before_adjust) (void);
void (*frob_file_before_fix) (void);
void (*frob_file_after_relocs) (void);
bfd_vma (*s_get_size) (symbolS *);
void (*s_set_size) (symbolS *, bfd_vma);
bfd_vma (*s_get_align) (symbolS *);
void (*s_set_align) (symbolS *, bfd_vma);
int (*s_get_other) (symbolS *);
void (*s_set_other) (symbolS *, int);
int (*s_get_desc) (symbolS *);
void (*s_set_desc) (symbolS *, int);
int (*s_get_type) (symbolS *);
void (*s_set_type) (symbolS *, int);
void (*copy_symbol_attributes) (symbolS *, symbolS *);
void (*generate_asm_lineno) (void);
void (*process_stab) (segT, int, const char *, int, int, int);
int (*separate_stab_sections) (void);
void (*init_stab_section) (segT);
int (*sec_sym_ok_for_reloc) (asection *);
void (*pop_insert) (void);
/* For configurations using ECOFF_DEBUGGING, this callback is used. */
void (*ecoff_set_ext) (symbolS *, struct ecoff_extr *);
void (*read_begin_hook) (void);
void (*symbol_new_hook) (symbolS *);
void (*symbol_clone_hook) (symbolS *, symbolS *);
void (*adjust_symtab) (void);
};
extern const struct format_ops elf_format_ops;
extern const struct format_ops ecoff_format_ops;
extern const struct format_ops coff_format_ops;
extern const struct format_ops aout_format_ops;
#ifndef this_format
COMMON const struct format_ops *this_format;
#endif
/* end of obj.h */

View File

@ -0,0 +1,74 @@
/* output-file.c - Deal with the output file
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1996, 1998, 1999, 2001,
2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "output-file.h"
#ifndef TARGET_MACH
#define TARGET_MACH 0
#endif
bfd *stdoutput;
void
output_file_create (char *name)
{
if (name[0] == '-' && name[1] == '\0')
as_fatal (_("can't open a bfd on stdout %s"), name);
else if (!(stdoutput = bfd_openw (name, TARGET_FORMAT)))
{
bfd_error_type err = bfd_get_error ();
if (err == bfd_error_invalid_target)
as_fatal (_("selected target format '%s' unknown"), TARGET_FORMAT);
else
as_fatal (_("can't create %s: %s"), name, bfd_errmsg (err));
}
bfd_set_format (stdoutput, bfd_object);
bfd_set_arch_mach (stdoutput, TARGET_ARCH, TARGET_MACH);
if (flag_traditional_format)
stdoutput->flags |= BFD_TRADITIONAL_FORMAT;
}
void
output_file_close (char *filename)
{
bfd_boolean res;
if (stdoutput == NULL)
return;
/* Close the bfd. */
if (had_errors ())
res = bfd_cache_close_all ();
else
res = bfd_close (stdoutput);
/* Prevent an infinite loop - if the close failed we will call as_fatal
which will call xexit() which may call this function again... */
stdoutput = NULL;
if (! res)
as_fatal (_("can't close %s: %s"), filename,
bfd_errmsg (bfd_get_error ()));
}

View File

@ -0,0 +1,26 @@
/* This file is output-file.h
Copyright 1987, 1988, 1989, 1990, 1991, 1992, 2003, 2005, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
void output_file_append (char *where, long length, char *filename);
void output_file_close (char *filename);
void output_file_create (char *name);
/* end of output-file.h */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
/* read.h - of read.c
Copyright 1986, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2012
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
extern char *input_line_pointer; /* -> char we are parsing now. */
/* Define to make whitespace be allowed in many syntactically
unnecessary places. Normally undefined. For compatibility with
ancient GNU cc. */
/* #undef PERMIT_WHITESPACE */
#define PERMIT_WHITESPACE
#ifdef PERMIT_WHITESPACE
#define SKIP_WHITESPACE() \
((*input_line_pointer == ' ') ? ++input_line_pointer : 0)
#else
#define SKIP_WHITESPACE() know(*input_line_pointer != ' ' )
#endif
#define LEX_NAME (1) /* may continue a name */
#define LEX_BEGIN_NAME (2) /* may begin a name */
#define LEX_END_NAME (4) /* ends a name */
#define is_name_beginner(c) \
( lex_type[(unsigned char) (c)] & LEX_BEGIN_NAME )
#define is_part_of_name(c) \
( lex_type[(unsigned char) (c)] & LEX_NAME )
#define is_name_ender(c) \
( lex_type[(unsigned char) (c)] & LEX_END_NAME )
#ifndef is_a_char
#define CHAR_MASK (0xff)
#define NOT_A_CHAR (CHAR_MASK+1)
#define is_a_char(c) (((unsigned) (c)) <= CHAR_MASK)
#endif /* is_a_char() */
extern char lex_type[];
extern char is_end_of_line[];
extern int is_it_end_of_statement (void);
extern char *find_end_of_line (char *, int);
extern int target_big_endian;
/* These are initialized by the CPU specific target files (tc-*.c). */
extern const char comment_chars[];
extern const char line_comment_chars[];
extern const char line_separator_chars[];
/* Table of -I directories. */
extern char **include_dirs;
extern int include_dir_count;
extern int include_dir_maxlen;
/* The offset in the absolute section. */
extern addressT abs_section_offset;
/* The label on a line, used by some of the pseudo-ops. */
extern symbolS *line_label;
/* This is used to support MRI common sections. */
extern symbolS *mri_common_symbol;
/* True if a stabs line debug statement is currently being emitted. */
extern int outputting_stabs_line_debug;
/* Possible arguments to .linkonce. */
enum linkonce_type {
LINKONCE_UNSET = 0,
LINKONCE_DISCARD,
LINKONCE_ONE_ONLY,
LINKONCE_SAME_SIZE,
LINKONCE_SAME_CONTENTS
};
#ifndef TC_CASE_SENSITIVE
extern char original_case_string[];
#endif
extern void pop_insert (const pseudo_typeS *);
extern unsigned int get_stab_string_offset
(const char *string, const char *stabstr_secname);
extern void aout_process_stab (int, const char *, int, int, int);
extern char *demand_copy_string (int *lenP);
extern char *demand_copy_C_string (int *len_pointer);
extern char get_absolute_expression_and_terminator (long *val_pointer);
extern offsetT get_absolute_expression (void);
extern unsigned int next_char_of_string (void);
extern void s_mri_sect (char *);
extern char *mri_comment_field (char *);
extern void mri_comment_end (char *, int);
extern void add_include_dir (char *path);
extern void cons (int nbytes);
extern void demand_empty_rest_of_line (void);
extern void emit_expr (expressionS *exp, unsigned int nbytes);
extern void emit_expr_fix (expressionS *, unsigned int, fragS *, char *);
extern void equals (char *sym_name, int reassign);
extern void float_cons (int float_type);
extern void ignore_rest_of_line (void);
#define discard_rest_of_line ignore_rest_of_line
extern int output_leb128 (char *, valueT, int sign);
extern void pseudo_set (symbolS * symbolP);
extern void read_a_source_file (char *name);
extern void read_begin (void);
extern void read_print_statistics (FILE *);
extern int sizeof_leb128 (valueT, int sign);
extern void stabs_generate_asm_file (void);
extern void stabs_generate_asm_lineno (void);
extern void stabs_generate_asm_func (const char *, const char *);
extern void stabs_generate_asm_endfunc (const char *, const char *);
extern void do_repeat (int,const char *,const char *);
extern void do_repeat_with_expander (int, const char *, const char *, const char *);
extern void end_repeat (int);
extern void do_parse_cons_expression (expressionS *, int);
extern void generate_lineno_debug (void);
extern void s_abort (int) ATTRIBUTE_NORETURN;
extern void s_align_bytes (int arg);
extern void s_align_ptwo (int);
extern void bss_alloc (symbolS *, addressT, int);
extern offsetT parse_align (int);
extern symbolS *s_comm_internal (int, symbolS *(*) (int, symbolS *, addressT));
extern symbolS *s_lcomm_internal (int, symbolS *, addressT);
extern void s_app_file_string (char *, int);
extern void s_app_file (int);
extern void s_app_line (int);
extern void s_bundle_align_mode (int);
extern void s_bundle_lock (int);
extern void s_bundle_unlock (int);
extern void s_comm (int);
extern void s_data (int);
extern void s_desc (int);
extern void s_else (int arg);
extern void s_elseif (int arg);
extern void s_end (int arg);
extern void s_endif (int arg);
extern void s_err (int);
extern void s_errwarn (int);
extern void s_fail (int);
extern void s_fill (int);
extern void s_float_space (int mult);
extern void s_func (int);
extern void s_globl (int arg);
extern void s_if (int arg);
extern void s_ifb (int arg);
extern void s_ifc (int arg);
extern void s_ifdef (int arg);
extern void s_ifeqs (int arg);
extern void s_ignore (int arg);
extern void s_include (int arg);
extern void s_irp (int arg);
extern void s_lcomm (int needs_align);
extern void s_lcomm_bytes (int needs_align);
extern void s_leb128 (int sign);
extern void s_linkonce (int);
extern void s_lsym (int);
extern void s_macro (int);
extern void s_mexit (int);
extern void s_mri (int);
extern void s_mri_common (int);
extern void s_org (int);
extern void s_print (int);
extern void s_purgem (int);
extern void s_rept (int);
extern void s_set (int);
extern void s_space (int mult);
extern void s_stab (int what);
extern void s_struct (int);
extern void s_text (int);
extern void stringer (int append_zero);
extern void s_xstab (int what);
extern void s_rva (int);
extern void s_incbin (int);
extern void s_weakref (int);

View File

@ -0,0 +1,91 @@
/* Remap file names for debug info for GNU assembler.
Copyright 2007 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "filenames.h"
/* Structure recording the mapping from source file and directory
names at compile time to those to be embedded in debug
information. */
typedef struct debug_prefix_map
{
const char *old_prefix;
const char *new_prefix;
size_t old_len;
size_t new_len;
struct debug_prefix_map *next;
} debug_prefix_map;
/* Linked list of such structures. */
debug_prefix_map *debug_prefix_maps;
/* Record a debug file prefix mapping. ARG is the argument to
-fdebug-prefix-map and must be of the form OLD=NEW. */
void
add_debug_prefix_map (const char *arg)
{
debug_prefix_map *map;
const char *p;
char *o;
p = strchr (arg, '=');
if (!p)
{
as_fatal (_("invalid argument '%s' to -fdebug-prefix-map"), arg);
return;
}
map = (struct debug_prefix_map *) xmalloc (sizeof (debug_prefix_map));
o = xstrdup (arg);
map->old_prefix = o;
map->old_len = p - arg;
o[map->old_len] = 0;
p++;
map->new_prefix = xstrdup (p);
map->new_len = strlen (p);
map->next = debug_prefix_maps;
debug_prefix_maps = map;
}
/* Perform user-specified mapping of debug filename prefixes. Returns
a newly allocated buffer containing the name corresponding to FILENAME.
It is the caller's responsibility to free the buffer. */
const char *
remap_debug_filename (const char *filename)
{
debug_prefix_map *map;
char *s;
const char *name;
size_t name_len;
for (map = debug_prefix_maps; map; map = map->next)
if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0)
break;
if (!map)
return xstrdup (filename);
name = filename + map->old_len;
name_len = strlen (name) + 1;
s = (char *) alloca (name_len + map->new_len);
memcpy (s, map->new_prefix, map->new_len);
memcpy (s + map->new_len, name, name_len);
return xstrdup (s);
}

View File

@ -0,0 +1,237 @@
/* sb.c - string buffer manipulation routines
Copyright 1994, 1995, 2000, 2003, 2005, 2006, 2007, 2009, 2012
Free Software Foundation, Inc.
Written by Steve and Judy Chamberlain of Cygnus Support,
sac@cygnus.com
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "sb.h"
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
/* These routines are about manipulating strings.
They are managed in things called `sb's which is an abbreviation
for string buffers. An sb has to be created, things can be glued
on to it, and at the end of it's life it should be freed. The
contents should never be pointed at whilst it is still growing,
since it could be moved at any time
eg:
sb_new (&foo);
sb_grow... (&foo,...);
use foo->ptr[*];
sb_kill (&foo); */
/* Buffers start at INIT_ALLOC size, and roughly double each time we
go over the current allocation. MALLOC_OVERHEAD is a guess at the
system malloc overhead. We aim to not waste any memory in the
underlying page/chunk allocated by the system malloc. */
#define MALLOC_OVERHEAD (2 * sizeof (size_t))
#define INIT_ALLOC (64 - MALLOC_OVERHEAD - 1)
static void sb_check (sb *, size_t);
/* Initializes an sb. */
void
sb_build (sb *ptr, size_t size)
{
ptr->ptr = xmalloc (size + 1);
ptr->max = size;
ptr->len = 0;
}
void
sb_new (sb *ptr)
{
sb_build (ptr, INIT_ALLOC);
}
/* Deallocate the sb at ptr. */
void
sb_kill (sb *ptr)
{
free (ptr->ptr);
}
/* Add the sb at s to the end of the sb at ptr. */
void
sb_add_sb (sb *ptr, sb *s)
{
sb_check (ptr, s->len);
memcpy (ptr->ptr + ptr->len, s->ptr, s->len);
ptr->len += s->len;
}
/* Helper for sb_scrub_and_add_sb. */
static sb *sb_to_scrub;
static char *scrub_position;
static size_t
scrub_from_sb (char *buf, size_t buflen)
{
size_t copy;
copy = sb_to_scrub->len - (scrub_position - sb_to_scrub->ptr);
if (copy > buflen)
copy = buflen;
memcpy (buf, scrub_position, copy);
scrub_position += copy;
return copy;
}
/* Run the sb at s through do_scrub_chars and add the result to the sb
at ptr. */
void
sb_scrub_and_add_sb (sb *ptr, sb *s)
{
sb_to_scrub = s;
scrub_position = s->ptr;
sb_check (ptr, s->len);
ptr->len += do_scrub_chars (scrub_from_sb, ptr->ptr + ptr->len, s->len);
sb_to_scrub = 0;
scrub_position = 0;
}
/* Make sure that the sb at ptr has room for another len characters,
and grow it if it doesn't. */
static void
sb_check (sb *ptr, size_t len)
{
size_t want = ptr->len + len;
if (want > ptr->max)
{
size_t max;
want += MALLOC_OVERHEAD + 1;
if ((ssize_t) want < 0)
as_fatal ("string buffer overflow");
#if GCC_VERSION >= 3004
max = (size_t) 1 << (CHAR_BIT * sizeof (want)
- (sizeof (want) <= sizeof (long)
? __builtin_clzl ((long) want)
: __builtin_clzll ((long long) want)));
#else
max = 128;
while (want > max)
max <<= 1;
#endif
max -= MALLOC_OVERHEAD + 1;
ptr->max = max;
ptr->ptr = xrealloc (ptr->ptr, max + 1);
}
}
/* Make the sb at ptr point back to the beginning. */
void
sb_reset (sb *ptr)
{
ptr->len = 0;
}
/* Add character c to the end of the sb at ptr. */
void
sb_add_char (sb *ptr, size_t c)
{
sb_check (ptr, 1);
ptr->ptr[ptr->len++] = c;
}
/* Add null terminated string s to the end of sb at ptr. */
void
sb_add_string (sb *ptr, const char *s)
{
size_t len = strlen (s);
sb_check (ptr, len);
memcpy (ptr->ptr + ptr->len, s, len);
ptr->len += len;
}
/* Add string at s of length len to sb at ptr */
void
sb_add_buffer (sb *ptr, const char *s, size_t len)
{
sb_check (ptr, len);
memcpy (ptr->ptr + ptr->len, s, len);
ptr->len += len;
}
/* Write terminating NUL and return string. */
char *
sb_terminate (sb *in)
{
in->ptr[in->len] = 0;
return in->ptr;
}
/* Start at the index idx into the string in sb at ptr and skip
whitespace. return the index of the first non whitespace character. */
size_t
sb_skip_white (size_t idx, sb *ptr)
{
while (idx < ptr->len
&& (ptr->ptr[idx] == ' '
|| ptr->ptr[idx] == '\t'))
idx++;
return idx;
}
/* Start at the index idx into the sb at ptr. skips whitespace,
a comma and any following whitespace. returns the index of the
next character. */
size_t
sb_skip_comma (size_t idx, sb *ptr)
{
while (idx < ptr->len
&& (ptr->ptr[idx] == ' '
|| ptr->ptr[idx] == '\t'))
idx++;
if (idx < ptr->len
&& ptr->ptr[idx] == ',')
idx++;
while (idx < ptr->len
&& (ptr->ptr[idx] == ' '
|| ptr->ptr[idx] == '\t'))
idx++;
return idx;
}

View File

@ -0,0 +1,71 @@
/* sb.h - header file for string buffer manipulation routines
Copyright 1994, 1995, 2000, 2003, 2005, 2006, 2007, 2012
Free Software Foundation, Inc.
Written by Steve and Judy Chamberlain of Cygnus Support,
sac@cygnus.com
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef SB_H
#define SB_H
/* String blocks
I had a couple of choices when deciding upon this data structure.
gas uses null terminated strings for all its internal work. This
often means that parts of the program that want to examine
substrings have to manipulate the data in the string to do the
right thing (a common operation is to single out a bit of text by
saving away the character after it, nulling it out, operating on
the substring and then replacing the character which was under the
null). This is a pain and I remember a load of problems that I had with
code in gas which almost got this right. Also, it's harder to grow and
allocate null terminated strings efficiently.
Obstacks provide all the functionality needed, but are too
complicated, hence the sb.
An sb is allocated by the caller. */
typedef struct sb
{
char *ptr; /* Points to the current block. */
size_t len; /* How much is used. */
size_t max; /* The maximum length. */
}
sb;
extern void sb_new (sb *);
extern void sb_build (sb *, size_t);
extern void sb_kill (sb *);
extern void sb_add_sb (sb *, sb *);
extern void sb_scrub_and_add_sb (sb *, sb *);
extern void sb_reset (sb *);
extern void sb_add_char (sb *, size_t);
extern void sb_add_string (sb *, const char *);
extern void sb_add_buffer (sb *, const char *, size_t);
extern char *sb_terminate (sb *);
extern size_t sb_skip_white (size_t, sb *);
extern size_t sb_skip_comma (size_t, sb *);
/* Actually in input-scrub.c. */
extern void input_scrub_include_sb (sb *, char *, int);
#endif /* SB_H */

View File

@ -0,0 +1,710 @@
/* Generic stabs parsing for gas.
Copyright 1989, 1990, 1991, 1993, 1995, 1996, 1997, 1998, 2000, 2001
2002, 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3,
or (at your option) any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "filenames.h"
#include "obstack.h"
#include "subsegs.h"
#include "ecoff.h"
/* We need this, despite the apparent object format dependency, since
it defines stab types, which all object formats can use now. */
#include "aout/stab_gnu.h"
/* Holds whether the assembler is generating stabs line debugging
information or not. Potentially used by md_cleanup function. */
int outputting_stabs_line_debug = 0;
static void s_stab_generic (int, char *, char *);
static void generate_asm_file (int, char *);
/* Allow backends to override the names used for the stab sections. */
#ifndef STAB_SECTION_NAME
#define STAB_SECTION_NAME ".stab"
#endif
#ifndef STAB_STRING_SECTION_NAME
#define STAB_STRING_SECTION_NAME ".stabstr"
#endif
/* Non-zero if we're in the middle of a .func function, in which case
stabs_generate_asm_lineno emits function relative line number stabs.
Otherwise it emits line number stabs with absolute addresses. Note that
both cases only apply to assembler code assembled with -gstabs. */
static int in_dot_func_p;
/* Label at start of current function if in_dot_func_p != 0. */
static const char *current_function_label;
/*
* Handle .stabX directives, which used to be open-coded.
* So much creeping featurism overloaded the semantics that we decided
* to put all .stabX thinking in one place. Here.
*
* We try to make any .stabX directive legal. Other people's AS will often
* do assembly-time consistency checks: eg assigning meaning to n_type bits
* and "protecting" you from setting them to certain values. (They also zero
* certain bits before emitting symbols. Tut tut.)
*
* If an expression is not absolute we either gripe or use the relocation
* information. Other people's assemblers silently forget information they
* don't need and invent information they need that you didn't supply.
*/
/*
* Build a string dictionary entry for a .stabX symbol.
* The symbol is added to the .<secname>str section.
*/
#ifndef SEPARATE_STAB_SECTIONS
#define SEPARATE_STAB_SECTIONS 0
#endif
unsigned int
get_stab_string_offset (const char *string, const char *stabstr_secname)
{
unsigned int length;
unsigned int retval;
segT save_seg;
subsegT save_subseg;
segT seg;
char *p;
if (! SEPARATE_STAB_SECTIONS)
abort ();
length = strlen (string);
save_seg = now_seg;
save_subseg = now_subseg;
/* Create the stab string section. */
seg = subseg_new (stabstr_secname, 0);
retval = seg_info (seg)->stabu.stab_string_size;
if (retval <= 0)
{
/* Make sure the first string is empty. */
p = frag_more (1);
*p = 0;
retval = seg_info (seg)->stabu.stab_string_size = 1;
bfd_set_section_flags (stdoutput, seg, SEC_READONLY | SEC_DEBUGGING);
if (seg->name == stabstr_secname)
seg->name = xstrdup (stabstr_secname);
}
if (length > 0)
{ /* Ordinary case. */
p = frag_more (length + 1);
strcpy (p, string);
seg_info (seg)->stabu.stab_string_size += length + 1;
}
else
retval = 0;
subseg_set (save_seg, save_subseg);
return retval;
}
#ifdef AOUT_STABS
#ifndef OBJ_PROCESS_STAB
#define OBJ_PROCESS_STAB(SEG,W,S,T,O,D) aout_process_stab(W,S,T,O,D)
#endif
/* Here instead of obj-aout.c because other formats use it too. */
void
aout_process_stab (what, string, type, other, desc)
int what;
const char *string;
int type, other, desc;
{
/* Put the stab information in the symbol table. */
symbolS *symbol;
/* Create the symbol now, but only insert it into the symbol chain
after any symbols mentioned in the value expression get into the
symbol chain. This is to avoid "continuation symbols" (where one
ends in "\" and the debug info is continued in the next .stabs
directive) from being separated by other random symbols. */
symbol = symbol_create (string, undefined_section, 0,
&zero_address_frag);
if (what == 's' || what == 'n')
{
/* Pick up the value from the input line. */
pseudo_set (symbol);
}
else
{
/* .stabd sets the name to NULL. Why? */
S_SET_NAME (symbol, NULL);
symbol_set_frag (symbol, frag_now);
S_SET_VALUE (symbol, (valueT) frag_now_fix ());
}
symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP);
symbol_get_bfdsym (symbol)->flags |= BSF_DEBUGGING;
S_SET_TYPE (symbol, type);
S_SET_OTHER (symbol, other);
S_SET_DESC (symbol, desc);
}
#endif
/* This can handle different kinds of stabs (s,n,d) and different
kinds of stab sections. */
static void
s_stab_generic (int what, char *stab_secname, char *stabstr_secname)
{
long longint;
char *string, *saved_string_obstack_end;
int type;
int other;
int desc;
/* The general format is:
.stabs "STRING",TYPE,OTHER,DESC,VALUE
.stabn TYPE,OTHER,DESC,VALUE
.stabd TYPE,OTHER,DESC
At this point input_line_pointer points after the pseudo-op and
any trailing whitespace. The argument what is one of 's', 'n' or
'd' indicating which type of .stab this is. */
if (what != 's')
{
string = "";
saved_string_obstack_end = 0;
}
else
{
int length;
string = demand_copy_C_string (&length);
/* FIXME: We should probably find some other temporary storage
for string, rather than leaking memory if someone else
happens to use the notes obstack. */
saved_string_obstack_end = notes.next_free;
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
input_line_pointer++;
else
{
as_warn (_(".stab%c: missing comma"), what);
ignore_rest_of_line ();
return;
}
}
if (get_absolute_expression_and_terminator (&longint) != ',')
{
as_warn (_(".stab%c: missing comma"), what);
ignore_rest_of_line ();
return;
}
type = longint;
if (get_absolute_expression_and_terminator (&longint) != ',')
{
as_warn (_(".stab%c: missing comma"), what);
ignore_rest_of_line ();
return;
}
other = longint;
desc = get_absolute_expression ();
if ((desc > 0xffff) || (desc < -0x8000))
/* This could happen for example with a source file with a huge
number of lines. The only cure is to use a different debug
format, probably DWARF. */
as_warn (_(".stab%c: description field '%x' too big, try a different debug format"),
what, desc);
if (what == 's' || what == 'n')
{
if (*input_line_pointer != ',')
{
as_warn (_(".stab%c: missing comma"), what);
ignore_rest_of_line ();
return;
}
input_line_pointer++;
SKIP_WHITESPACE ();
}
#ifdef TC_PPC
#ifdef OBJ_ELF
/* Solaris on PowerPC has decided that .stabd can take 4 arguments, so if we were
given 4 arguments, make it a .stabn */
else if (what == 'd')
{
char *save_location = input_line_pointer;
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
input_line_pointer++;
what = 'n';
}
else
input_line_pointer = save_location;
}
#endif /* OBJ_ELF */
#endif /* TC_PPC */
#ifndef NO_LISTING
if (listing)
{
switch (type)
{
case N_SLINE:
listing_source_line ((unsigned int) desc);
break;
case N_SO:
case N_SOL:
listing_source_file (string);
break;
}
}
#endif /* ! NO_LISTING */
/* We have now gathered the type, other, and desc information. For
.stabs or .stabn, input_line_pointer is now pointing at the
value. */
if (SEPARATE_STAB_SECTIONS)
/* Output the stab information in a separate section. This is used
at least for COFF and ELF. */
{
segT saved_seg = now_seg;
subsegT saved_subseg = now_subseg;
fragS *saved_frag = frag_now;
valueT dot;
segT seg;
unsigned int stroff;
char *p;
static segT cached_sec;
static char *cached_secname;
dot = frag_now_fix ();
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
if (cached_secname && !strcmp (cached_secname, stab_secname))
{
seg = cached_sec;
subseg_set (seg, 0);
}
else
{
seg = subseg_new (stab_secname, 0);
if (cached_secname)
free (cached_secname);
cached_secname = xstrdup (stab_secname);
cached_sec = seg;
}
if (! seg_info (seg)->hadone)
{
bfd_set_section_flags (stdoutput, seg,
SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
#ifdef INIT_STAB_SECTION
INIT_STAB_SECTION (seg);
#endif
seg_info (seg)->hadone = 1;
}
stroff = get_stab_string_offset (string, stabstr_secname);
if (what == 's')
{
/* Release the string, if nobody else has used the obstack. */
if (saved_string_obstack_end == notes.next_free)
obstack_free (&notes, string);
}
/* At least for now, stabs in a special stab section are always
output as 12 byte blocks of information. */
p = frag_more (8);
md_number_to_chars (p, (valueT) stroff, 4);
md_number_to_chars (p + 4, (valueT) type, 1);
md_number_to_chars (p + 5, (valueT) other, 1);
md_number_to_chars (p + 6, (valueT) desc, 2);
if (what == 's' || what == 'n')
{
/* Pick up the value from the input line. */
cons (4);
input_line_pointer--;
}
else
{
symbolS *symbol;
expressionS exp;
/* Arrange for a value representing the current location. */
symbol = symbol_temp_new (saved_seg, dot, saved_frag);
exp.X_op = O_symbol;
exp.X_add_symbol = symbol;
exp.X_add_number = 0;
emit_expr (&exp, 4);
}
#ifdef OBJ_PROCESS_STAB
OBJ_PROCESS_STAB (seg, what, string, type, other, desc);
#endif
subseg_set (saved_seg, saved_subseg);
}
else
{
#ifdef OBJ_PROCESS_STAB
OBJ_PROCESS_STAB (0, what, string, type, other, desc);
#else
abort ();
#endif
}
demand_empty_rest_of_line ();
}
/* Regular stab directive. */
void
s_stab (int what)
{
s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME);
}
/* "Extended stabs", used in Solaris only now. */
void
s_xstab (int what)
{
int length;
char *stab_secname, *stabstr_secname;
static char *saved_secname, *saved_strsecname;
/* @@ MEMORY LEAK: This allocates a copy of the string, but in most
cases it will be the same string, so we could release the storage
back to the obstack it came from. */
stab_secname = demand_copy_C_string (&length);
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
input_line_pointer++;
else
{
as_bad (_("comma missing in .xstabs"));
ignore_rest_of_line ();
return;
}
/* To get the name of the stab string section, simply add "str" to
the stab section name. */
if (saved_secname == 0 || strcmp (saved_secname, stab_secname))
{
stabstr_secname = (char *) xmalloc (strlen (stab_secname) + 4);
strcpy (stabstr_secname, stab_secname);
strcat (stabstr_secname, "str");
if (saved_secname)
{
free (saved_secname);
free (saved_strsecname);
}
saved_secname = stab_secname;
saved_strsecname = stabstr_secname;
}
s_stab_generic (what, saved_secname, saved_strsecname);
}
#ifdef S_SET_DESC
/* Frob invented at RMS' request. Set the n_desc of a symbol. */
void
s_desc (ignore)
int ignore ATTRIBUTE_UNUSED;
{
char *name;
char c;
char *p;
symbolS *symbolP;
int temp;
name = input_line_pointer;
c = get_symbol_end ();
p = input_line_pointer;
*p = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
*p = 0;
as_bad (_("expected comma after \"%s\""), name);
*p = c;
ignore_rest_of_line ();
}
else
{
input_line_pointer++;
temp = get_absolute_expression ();
*p = 0;
symbolP = symbol_find_or_make (name);
*p = c;
S_SET_DESC (symbolP, temp);
}
demand_empty_rest_of_line ();
} /* s_desc() */
#endif /* defined (S_SET_DESC) */
/* Generate stabs debugging information to denote the main source file. */
void
stabs_generate_asm_file (void)
{
char *file;
unsigned int lineno;
as_where (&file, &lineno);
if (use_gnu_debug_info_extensions)
{
const char *dir;
char *dir2;
dir = remap_debug_filename (getpwd ());
dir2 = (char *) alloca (strlen (dir) + 2);
sprintf (dir2, "%s%s", dir, "/");
generate_asm_file (N_SO, dir2);
xfree ((char *) dir);
}
generate_asm_file (N_SO, file);
}
/* Generate stabs debugging information to denote the source file.
TYPE is one of N_SO, N_SOL. */
static void
generate_asm_file (int type, char *file)
{
static char *last_file;
static int label_count;
char *hold;
char sym[30];
char *buf;
char *tmp = file;
char *file_endp = file + strlen (file);
char *bufp;
if (last_file != NULL
&& filename_cmp (last_file, file) == 0)
return;
/* Rather than try to do this in some efficient fashion, we just
generate a string and then parse it again. That lets us use the
existing stabs hook, which expect to see a string, rather than
inventing new ones. */
hold = input_line_pointer;
sprintf (sym, "%sF%d", FAKE_LABEL_NAME, label_count);
++label_count;
/* Allocate enough space for the file name (possibly extended with
doubled up backslashes), the symbol name, and the other characters
that make up a stabs file directive. */
bufp = buf = (char *) xmalloc (2 * strlen (file) + strlen (sym) + 12);
*bufp++ = '"';
while (tmp < file_endp)
{
char *bslash = strchr (tmp, '\\');
size_t len = (bslash) ? (size_t) (bslash - tmp + 1) : strlen (tmp);
/* Double all backslashes, since demand_copy_C_string (used by
s_stab to extract the part in quotes) will try to replace them as
escape sequences. backslash may appear in a filespec. */
strncpy (bufp, tmp, len);
tmp += len;
bufp += len;
if (bslash != NULL)
*bufp++ = '\\';
}
sprintf (bufp, "\",%d,0,0,%s\n", type, sym);
input_line_pointer = buf;
s_stab ('s');
colon (sym);
if (last_file != NULL)
free (last_file);
last_file = xstrdup (file);
free (buf);
input_line_pointer = hold;
}
/* Generate stabs debugging information for the current line. This is
used to produce debugging information for an assembler file. */
void
stabs_generate_asm_lineno (void)
{
static int label_count;
char *hold;
char *file;
unsigned int lineno;
char *buf;
char sym[30];
/* Remember the last file/line and avoid duplicates. */
static unsigned int prev_lineno = -1;
static char *prev_file = NULL;
/* Rather than try to do this in some efficient fashion, we just
generate a string and then parse it again. That lets us use the
existing stabs hook, which expect to see a string, rather than
inventing new ones. */
hold = input_line_pointer;
as_where (&file, &lineno);
/* Don't emit sequences of stabs for the same line. */
if (prev_file == NULL)
{
/* First time thru. */
prev_file = xstrdup (file);
prev_lineno = lineno;
}
else if (lineno == prev_lineno
&& filename_cmp (file, prev_file) == 0)
{
/* Same file/line as last time. */
return;
}
else
{
/* Remember file/line for next time. */
prev_lineno = lineno;
if (filename_cmp (file, prev_file) != 0)
{
free (prev_file);
prev_file = xstrdup (file);
}
}
/* Let the world know that we are in the middle of generating a
piece of stabs line debugging information. */
outputting_stabs_line_debug = 1;
generate_asm_file (N_SOL, file);
sprintf (sym, "%sL%d", FAKE_LABEL_NAME, label_count);
++label_count;
if (in_dot_func_p)
{
buf = (char *) alloca (100 + strlen (current_function_label));
sprintf (buf, "%d,0,%d,%s-%s\n", N_SLINE, lineno,
sym, current_function_label);
}
else
{
buf = (char *) alloca (100);
sprintf (buf, "%d,0,%d,%s\n", N_SLINE, lineno, sym);
}
input_line_pointer = buf;
s_stab ('n');
colon (sym);
input_line_pointer = hold;
outputting_stabs_line_debug = 0;
}
/* Emit a function stab.
All assembler functions are assumed to have return type `void'. */
void
stabs_generate_asm_func (const char *funcname, const char *startlabname)
{
static int void_emitted_p;
char *hold = input_line_pointer;
char *buf;
char *file;
unsigned int lineno;
if (! void_emitted_p)
{
input_line_pointer = "\"void:t1=1\",128,0,0,0";
s_stab ('s');
void_emitted_p = 1;
}
as_where (&file, &lineno);
if (asprintf (&buf, "\"%s:F1\",%d,0,%d,%s",
funcname, N_FUN, lineno + 1, startlabname) == -1)
as_fatal ("%s", xstrerror (errno));
input_line_pointer = buf;
s_stab ('s');
free (buf);
input_line_pointer = hold;
current_function_label = xstrdup (startlabname);
in_dot_func_p = 1;
}
/* Emit a stab to record the end of a function. */
void
stabs_generate_asm_endfunc (const char *funcname ATTRIBUTE_UNUSED,
const char *startlabname)
{
static int label_count;
char *hold = input_line_pointer;
char *buf;
char sym[30];
sprintf (sym, "%sendfunc%d", FAKE_LABEL_NAME, label_count);
++label_count;
colon (sym);
if (asprintf (&buf, "\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname) == -1)
as_fatal ("%s", xstrerror (errno));
input_line_pointer = buf;
s_stab ('s');
free (buf);
input_line_pointer = hold;
in_dot_func_p = 0;
current_function_label = NULL;
}

View File

@ -0,0 +1,159 @@
/* struct_symbol.h - Internal symbol structure
Copyright 1987, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2005,
2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef __struc_symbol_h__
#define __struc_symbol_h__
struct symbol_flags
{
/* Wether the symbol is a local_symbol. */
unsigned int sy_local_symbol : 1;
/* Wether symbol has been written. */
unsigned int sy_written : 1;
/* Whether symbol value has been completely resolved (used during
final pass over symbol table). */
unsigned int sy_resolved : 1;
/* Whether the symbol value is currently being resolved (used to
detect loops in symbol dependencies). */
unsigned int sy_resolving : 1;
/* Whether the symbol value is used in a reloc. This is used to
ensure that symbols used in relocs are written out, even if they
are local and would otherwise not be. */
unsigned int sy_used_in_reloc : 1;
/* Whether the symbol is used as an operand or in an expression.
NOTE: Not all the backends keep this information accurate;
backends which use this bit are responsible for setting it when
a symbol is used in backend routines. */
unsigned int sy_used : 1;
/* Whether the symbol can be re-defined. */
unsigned int sy_volatile : 1;
/* Whether the symbol is a forward reference. */
unsigned int sy_forward_ref : 1;
/* This is set if the symbol is defined in an MRI common section.
We handle such sections as single common symbols, so symbols
defined within them must be treated specially by the relocation
routines. */
unsigned int sy_mri_common : 1;
/* This is set if the symbol is set with a .weakref directive. */
unsigned int sy_weakrefr : 1;
/* This is set when the symbol is referenced as part of a .weakref
directive, but only if the symbol was not in the symbol table
before. It is cleared as soon as any direct reference to the
symbol is present. */
unsigned int sy_weakrefd : 1;
};
/* The information we keep for a symbol. Note that the symbol table
holds pointers both to this and to local_symbol structures. See
below. */
struct symbol
{
/* Symbol flags. */
struct symbol_flags sy_flags;
/* BFD symbol */
asymbol *bsym;
/* The value of the symbol. */
expressionS sy_value;
/* Forwards and (optionally) backwards chain pointers. */
struct symbol *sy_next;
struct symbol *sy_previous;
/* Pointer to the frag this symbol is attached to, if any.
Otherwise, NULL. */
struct frag *sy_frag;
#ifdef OBJ_SYMFIELD_TYPE
OBJ_SYMFIELD_TYPE sy_obj;
#endif
#ifdef TC_SYMFIELD_TYPE
TC_SYMFIELD_TYPE sy_tc;
#endif
#ifdef TARGET_SYMBOL_FIELDS
TARGET_SYMBOL_FIELDS
#endif
};
/* A pointer in the symbol may point to either a complete symbol
(struct symbol above) or to a local symbol (struct local_symbol
defined here). The symbol code can detect the case by examining
the first field. It is always NULL for a local symbol.
We do this because we ordinarily only need a small amount of
information for a local symbol. The symbol table takes up a lot of
space, and storing less information for a local symbol can make a
big difference in assembler memory usage when assembling a large
file. */
struct local_symbol
{
/* Symbol flags. Only sy_local_symbol and sy_resolved are relevant. */
struct symbol_flags lsy_flags;
/* The symbol section. This also serves as a flag. If this is
reg_section, then this symbol has been converted into a regular
symbol, and lsy_sym points to it. */
segT lsy_section;
/* The symbol name. */
const char *lsy_name;
/* The symbol frag or the real symbol, depending upon the value in
lsy_section. */
union
{
fragS *lsy_frag;
symbolS *lsy_sym;
} u;
/* The value of the symbol. */
valueT lsy_value;
#ifdef TC_LOCAL_SYMFIELD_TYPE
TC_LOCAL_SYMFIELD_TYPE lsy_tc;
#endif
};
#define local_symbol_converted_p(l) ((l)->lsy_section == reg_section)
#define local_symbol_mark_converted(l) ((l)->lsy_section = reg_section)
#define local_symbol_resolved_p(l) ((l)->lsy_flags.sy_resolved)
#define local_symbol_mark_resolved(l) ((l)->lsy_flags.sy_resolved = 1)
#define local_symbol_get_frag(l) ((l)->u.lsy_frag)
#define local_symbol_set_frag(l, f) ((l)->u.lsy_frag = (f))
#define local_symbol_get_real_symbol(l) ((l)->u.lsy_sym)
#define local_symbol_set_real_symbol(l, s) ((l)->u.lsy_sym = (s))
#endif /* __struc_symbol_h__ */

View File

@ -0,0 +1,330 @@
/* subsegs.c - subsegments -
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* Segments & sub-segments. */
#include "as.h"
#include "subsegs.h"
#include "obstack.h"
frchainS *frchain_now;
static struct obstack frchains;
static fragS dummy_frag;
void
subsegs_begin (void)
{
obstack_begin (&frchains, chunksize);
#if __GNUC__ >= 2
obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
#endif
frchain_now = NULL; /* Warn new_subseg() that we are booting. */
frag_now = &dummy_frag;
}
/*
* subseg_change()
*
* Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
* subsegment. If we are already in the correct subsegment, change nothing.
* This is used eg as a worker for subseg_set [which does make a new frag_now]
* and for changing segments after we have read the source. We construct eg
* fixSs even after the source file is read, so we do have to keep the
* segment context correct.
*/
void
subseg_change (register segT seg, register int subseg)
{
segment_info_type *seginfo = seg_info (seg);
now_seg = seg;
now_subseg = subseg;
if (! seginfo)
{
seginfo = (segment_info_type *) xcalloc (1, sizeof (*seginfo));
seginfo->bfd_section = seg;
bfd_set_section_userdata (stdoutput, seg, seginfo);
}
}
static void
subseg_set_rest (segT seg, subsegT subseg)
{
frchainS *frcP; /* crawl frchain chain */
frchainS **lastPP; /* address of last pointer */
frchainS *newP; /* address of new frchain */
segment_info_type *seginfo;
mri_common_symbol = NULL;
if (frag_now && frchain_now)
frchain_now->frch_frag_now = frag_now;
gas_assert (frchain_now == 0
|| frchain_now->frch_last == frag_now);
subseg_change (seg, (int) subseg);
seginfo = seg_info (seg);
/* Attempt to find or make a frchain for that subsection.
We keep the list sorted by subsection number. */
for (frcP = *(lastPP = &seginfo->frchainP);
frcP != NULL;
frcP = *(lastPP = &frcP->frch_next))
if (frcP->frch_subseg >= subseg)
break;
if (frcP == NULL || frcP->frch_subseg != subseg)
{
/* This should be the only code that creates a frchainS. */
newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
newP->frch_subseg = subseg;
newP->fix_root = NULL;
newP->fix_tail = NULL;
obstack_begin (&newP->frch_obstack, chunksize);
#if __GNUC__ >= 2
obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
#endif
newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
newP->frch_frag_now->fr_type = rs_fill;
newP->frch_cfi_data = NULL;
newP->frch_root = newP->frch_last = newP->frch_frag_now;
*lastPP = newP;
newP->frch_next = frcP;
frcP = newP;
}
frchain_now = frcP;
frag_now = frcP->frch_frag_now;
gas_assert (frchain_now->frch_last == frag_now);
}
/*
* subseg_set(segT, subsegT)
*
* If you attempt to change to the current subsegment, nothing happens.
*
* In: segT, subsegT code for new subsegment.
* frag_now -> incomplete frag for current subsegment.
* If frag_now==NULL, then there is no old, incomplete frag, so
* the old frag is not closed off.
*
* Out: now_subseg, now_seg updated.
* Frchain_now points to the (possibly new) struct frchain for this
* sub-segment.
*/
segT
subseg_get (const char *segname, int force_new)
{
segT secptr;
segment_info_type *seginfo;
const char *now_seg_name = (now_seg
? bfd_get_section_name (stdoutput, now_seg)
: 0);
if (!force_new
&& now_seg_name
&& (now_seg_name == segname
|| !strcmp (now_seg_name, segname)))
return now_seg;
if (!force_new)
secptr = bfd_make_section_old_way (stdoutput, segname);
else
secptr = bfd_make_section_anyway (stdoutput, segname);
seginfo = seg_info (secptr);
if (! seginfo)
{
secptr->output_section = secptr;
seginfo = (segment_info_type *) xcalloc (1, sizeof (*seginfo));
seginfo->bfd_section = secptr;
bfd_set_section_userdata (stdoutput, secptr, seginfo);
}
return secptr;
}
segT
subseg_new (const char *segname, subsegT subseg)
{
segT secptr;
secptr = subseg_get (segname, 0);
subseg_set_rest (secptr, subseg);
return secptr;
}
/* Like subseg_new, except a new section is always created, even if
a section with that name already exists. */
segT
subseg_force_new (const char *segname, subsegT subseg)
{
segT secptr;
secptr = subseg_get (segname, 1);
subseg_set_rest (secptr, subseg);
return secptr;
}
void
subseg_set (segT secptr, subsegT subseg)
{
if (! (secptr == now_seg && subseg == now_subseg))
subseg_set_rest (secptr, subseg);
mri_common_symbol = NULL;
}
#ifndef obj_sec_sym_ok_for_reloc
#define obj_sec_sym_ok_for_reloc(SEC) 0
#endif
symbolS *
section_symbol (segT sec)
{
segment_info_type *seginfo = seg_info (sec);
symbolS *s;
if (seginfo == 0)
abort ();
if (seginfo->sym)
return seginfo->sym;
#ifndef EMIT_SECTION_SYMBOLS
#define EMIT_SECTION_SYMBOLS 1
#endif
if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
{
/* Here we know it won't be going into the symbol table. */
s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
}
else
{
segT seg;
s = symbol_find (sec->symbol->name);
/* We have to make sure it is the right symbol when we
have multiple sections with the same section name. */
if (s == NULL
|| ((seg = S_GET_SEGMENT (s)) != sec
&& seg != undefined_section))
s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
else if (seg == undefined_section)
{
S_SET_SEGMENT (s, sec);
symbol_set_frag (s, &zero_address_frag);
}
}
S_CLEAR_EXTERNAL (s);
/* Use the BFD section symbol, if possible. */
if (obj_sec_sym_ok_for_reloc (sec))
symbol_set_bfdsym (s, sec->symbol);
else
symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
seginfo->sym = s;
return s;
}
/* Return whether the specified segment is thought to hold text. */
int
subseg_text_p (segT sec)
{
return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
}
/* Return non zero if SEC has at least one byte of data. It is
possible that we'll return zero even on a non-empty section because
we don't know all the fragment types, and it is possible that an
fr_fix == 0 one still contributes data. Think of this as
seg_definitely_not_empty_p. */
int
seg_not_empty_p (segT sec ATTRIBUTE_UNUSED)
{
segment_info_type *seginfo = seg_info (sec);
frchainS *chain;
fragS *frag;
if (!seginfo)
return 0;
for (chain = seginfo->frchainP; chain; chain = chain->frch_next)
{
for (frag = chain->frch_root; frag; frag = frag->fr_next)
if (frag->fr_fix)
return 1;
if (obstack_next_free (&chain->frch_obstack)
!= chain->frch_last->fr_literal)
return 1;
}
return 0;
}
void
subsegs_print_statistics (FILE *file)
{
frchainS *frchp;
asection *s;
fprintf (file, "frag chains:\n");
for (s = stdoutput->sections; s; s = s->next)
{
segment_info_type *seginfo;
/* Skip gas-internal sections. */
if (segment_name (s)[0] == '*')
continue;
seginfo = seg_info (s);
if (!seginfo)
continue;
for (frchp = seginfo->frchainP; frchp; frchp = frchp->frch_next)
{
int count = 0;
fragS *fragp;
for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
count++;
fprintf (file, "\n");
fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
segment_name (s), count);
}
}
}
/* end of subsegs.c */

View File

@ -0,0 +1,117 @@
/* subsegs.h -> subsegs.c
Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2003, 2005,
2006, 2007, 2009 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/*
* For every sub-segment the user mentions in the ASsembler program,
* we make one struct frchain. Each sub-segment has exactly one struct frchain
* and vice versa.
*
* Struct frchain's are forward chained (in ascending order of sub-segment
* code number). The chain runs through frch_next of each subsegment.
* This makes it hard to find a subsegment's frags
* if programmer uses a lot of them. Most programs only use text0 and
* data0, so they don't suffer. At least this way:
* (1) There are no "arbitrary" restrictions on how many subsegments
* can be programmed;
* (2) Subsegments' frchain-s are (later) chained together in the order in
* which they are emitted for object file viz text then data.
*
* From each struct frchain dangles a chain of struct frags. The frags
* represent code fragments, for that sub-segment, forward chained.
*/
#include "obstack.h"
struct frch_cfi_data;
struct frchain /* control building of a frag chain */
{ /* FRCH = FRagment CHain control */
struct frag *frch_root; /* 1st struct frag in chain, or NULL */
struct frag *frch_last; /* last struct frag in chain, or NULL */
struct frchain *frch_next; /* next in chain of struct frchain-s */
subsegT frch_subseg; /* subsegment number of this chain */
fixS *fix_root; /* Root of fixups for this subsegment. */
fixS *fix_tail; /* Last fixup for this subsegment. */
struct obstack frch_obstack; /* for objects in this frag chain */
fragS *frch_frag_now; /* frag_now for this subsegment */
struct frch_cfi_data *frch_cfi_data;
};
typedef struct frchain frchainS;
/* Frchain we are assembling into now. That is, the current segment's
frag chain, even if it contains no (complete) frags. */
extern frchainS *frchain_now;
typedef struct segment_info_struct {
frchainS *frchainP;
unsigned int hadone : 1;
/* This field is set if this is a .bss section which does not really
have any contents. Once upon a time a .bss section did not have
any frags, but that is no longer true. This field prevent the
SEC_HAS_CONTENTS flag from being set for the section even if
there are frags. */
unsigned int bss : 1;
int user_stuff;
/* Fixups for this segment. This is only valid after the frchains
are run together. */
fixS *fix_root;
fixS *fix_tail;
symbolS *dot;
struct lineno_list *lineno_list_head;
struct lineno_list *lineno_list_tail;
/* Which BFD section does this gas segment correspond to? */
asection *bfd_section;
/* NULL, or pointer to the gas symbol that is the section symbol for
this section. sym->bsym and bfd_section->symbol should be the same. */
symbolS *sym;
union {
/* Current size of section holding stabs strings. */
unsigned long stab_string_size;
/* Initial frag for ELF. */
char *p;
}
stabu;
#ifdef NEED_LITERAL_POOL
unsigned long literal_pool_size;
#endif
#ifdef TC_SEGMENT_INFO_TYPE
TC_SEGMENT_INFO_TYPE tc_segment_info_data;
#endif
} segment_info_type;
#define seg_info(sec) \
((segment_info_type *) bfd_get_section_userdata (stdoutput, sec))
extern symbolS *section_symbol (segT);
extern void subsegs_print_statistics (FILE *);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,216 @@
/* symbols.h -
Copyright 1987, 1990, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
extern struct obstack notes; /* eg FixS live here. */
extern struct obstack cond_obstack; /* this is where we track .ifdef/.endif
(if we do that at all). */
extern symbolS *symbol_rootP; /* all the symbol nodes */
extern symbolS *symbol_lastP; /* last struct symbol we made, or NULL */
extern symbolS abs_symbol;
extern symbolS dot_symbol;
extern int symbol_table_frozen;
/* This is non-zero if symbols are case sensitive, which is the
default. */
extern int symbols_case_sensitive;
char * symbol_relc_make_expr (expressionS *);
char * symbol_relc_make_sym (symbolS *);
char * symbol_relc_make_value (offsetT);
char *decode_local_label_name (char *s);
symbolS *symbol_find (const char *name);
symbolS *symbol_find_noref (const char *name, int noref);
symbolS *symbol_find_exact (const char *name);
symbolS *symbol_find_exact_noref (const char *name, int noref);
symbolS *symbol_find_or_make (const char *name);
symbolS *symbol_make (const char *name);
symbolS *symbol_new (const char *name, segT segment, valueT value,
fragS * frag);
symbolS *symbol_create (const char *name, segT segment, valueT value,
fragS * frag);
struct local_symbol *local_symbol_make (const char *name, segT section,
valueT val, fragS *frag);
symbolS *symbol_clone (symbolS *, int);
#undef symbol_clone_if_forward_ref
symbolS *symbol_clone_if_forward_ref (symbolS *, int);
#define symbol_clone_if_forward_ref(s) symbol_clone_if_forward_ref (s, 0)
symbolS *symbol_temp_new (segT, valueT, fragS *);
symbolS *symbol_temp_new_now (void);
symbolS *symbol_temp_make (void);
symbolS *colon (const char *sym_name);
void local_colon (int n);
void symbol_begin (void);
void dot_symbol_init (void);
void symbol_print_statistics (FILE *);
void symbol_table_insert (symbolS * symbolP);
valueT resolve_symbol_value (symbolS *);
void resolve_local_symbol_values (void);
int snapshot_symbol (symbolS **, valueT *, segT *, fragS **);
void print_symbol_value (symbolS *);
void print_expr (expressionS *);
void print_expr_1 (FILE *, expressionS *);
void print_symbol_value_1 (FILE *, symbolS *);
int dollar_label_defined (long l);
void dollar_label_clear (void);
void define_dollar_label (long l);
char *dollar_label_name (long l, int augend);
void fb_label_instance_inc (long label);
char *fb_label_name (long n, long augend);
extern void copy_symbol_attributes (symbolS *, symbolS *);
/* Get and set the values of symbols. These used to be macros. */
extern valueT S_GET_VALUE (symbolS *);
extern void S_SET_VALUE (symbolS *, valueT);
extern int S_IS_FUNCTION (symbolS *);
extern int S_IS_EXTERNAL (symbolS *);
extern int S_IS_WEAK (symbolS *);
extern int S_IS_WEAKREFR (symbolS *);
extern int S_IS_WEAKREFD (symbolS *);
extern int S_IS_COMMON (symbolS *);
extern int S_IS_DEFINED (symbolS *);
extern int S_FORCE_RELOC (symbolS *, int);
extern int S_IS_DEBUG (symbolS *);
extern int S_IS_LOCAL (symbolS *);
extern int S_IS_STABD (symbolS *);
extern int S_CAN_BE_REDEFINED (const symbolS *);
extern int S_IS_VOLATILE (const symbolS *);
extern int S_IS_FORWARD_REF (const symbolS *);
extern const char *S_GET_NAME (symbolS *);
extern segT S_GET_SEGMENT (symbolS *);
extern void S_SET_SEGMENT (symbolS *, segT);
extern void S_SET_EXTERNAL (symbolS *);
extern void S_SET_NAME (symbolS *, const char *);
extern void S_CLEAR_EXTERNAL (symbolS *);
extern void S_SET_WEAK (symbolS *);
extern void S_SET_WEAKREFR (symbolS *);
extern void S_CLEAR_WEAKREFR (symbolS *);
extern void S_SET_WEAKREFD (symbolS *);
extern void S_CLEAR_WEAKREFD (symbolS *);
extern void S_SET_THREAD_LOCAL (symbolS *);
extern void S_SET_VOLATILE (symbolS *);
extern void S_CLEAR_VOLATILE (symbolS *);
extern void S_SET_FORWARD_REF (symbolS *);
#ifndef WORKING_DOT_WORD
struct broken_word
{
/* Linked list -- one of these structures per ".word x-y+C"
expression. */
struct broken_word *next_broken_word;
/* Segment and subsegment for broken word. */
segT seg;
subsegT subseg;
/* Which frag is this broken word in? */
fragS *frag;
/* Where in the frag is it? */
char *word_goes_here;
/* Where to add the break. */
fragS *dispfrag; /* where to add the break */
/* Operands of expression. */
symbolS *add;
symbolS *sub;
offsetT addnum;
int added; /* nasty thing happened yet? */
/* 1: added and has a long-jump */
/* 2: added but uses someone elses long-jump */
/* Pointer to broken_word with a similar long-jump. */
struct broken_word *use_jump;
};
extern struct broken_word *broken_words;
#endif /* ndef WORKING_DOT_WORD */
/*
* Current means for getting from symbols to segments and vice verse.
* This will change for infinite-segments support (e.g. COFF).
*/
extern const segT N_TYPE_seg[]; /* subseg.c */
#define SEGMENT_TO_SYMBOL_TYPE(seg) ( seg_N_TYPE [(int) (seg)] )
extern const short seg_N_TYPE[];/* subseg.c */
#define N_REGISTER 30 /* Fake N_TYPE value for SEG_REGISTER */
void symbol_clear_list_pointers (symbolS * symbolP);
void symbol_insert (symbolS * addme, symbolS * target,
symbolS ** rootP, symbolS ** lastP);
void symbol_remove (symbolS * symbolP, symbolS ** rootP,
symbolS ** lastP);
extern symbolS *symbol_previous (symbolS *);
void verify_symbol_chain (symbolS * rootP, symbolS * lastP);
void symbol_append (symbolS * addme, symbolS * target,
symbolS ** rootP, symbolS ** lastP);
extern symbolS *symbol_next (symbolS *);
extern expressionS *symbol_get_value_expression (symbolS *);
extern void symbol_set_value_expression (symbolS *, const expressionS *);
extern offsetT *symbol_X_add_number (symbolS *);
extern void symbol_set_value_now (symbolS *);
extern void symbol_set_frag (symbolS *, fragS *);
extern fragS *symbol_get_frag (symbolS *);
extern void symbol_mark_used (symbolS *);
extern void symbol_clear_used (symbolS *);
extern int symbol_used_p (symbolS *);
extern void symbol_mark_used_in_reloc (symbolS *);
extern void symbol_clear_used_in_reloc (symbolS *);
extern int symbol_used_in_reloc_p (symbolS *);
extern void symbol_mark_mri_common (symbolS *);
extern void symbol_clear_mri_common (symbolS *);
extern int symbol_mri_common_p (symbolS *);
extern void symbol_mark_written (symbolS *);
extern void symbol_clear_written (symbolS *);
extern int symbol_written_p (symbolS *);
extern void symbol_mark_resolved (symbolS *);
extern int symbol_resolved_p (symbolS *);
extern int symbol_section_p (symbolS *);
extern int symbol_equated_p (symbolS *);
extern int symbol_equated_reloc_p (symbolS *);
extern int symbol_constant_p (symbolS *);
extern int symbol_shadow_p (symbolS *);
extern asymbol *symbol_get_bfdsym (symbolS *);
extern void symbol_set_bfdsym (symbolS *, asymbol *);
extern int symbol_same_p (symbolS *, symbolS *);
#ifdef OBJ_SYMFIELD_TYPE
OBJ_SYMFIELD_TYPE *symbol_get_obj (symbolS *);
void symbol_set_obj (symbolS *, OBJ_SYMFIELD_TYPE *);
#endif
#ifdef TC_SYMFIELD_TYPE
TC_SYMFIELD_TYPE *symbol_get_tc (symbolS *);
void symbol_set_tc (symbolS *, TC_SYMFIELD_TYPE *);
#endif

View File

@ -0,0 +1 @@
#include "tc-i386.h"

View File

@ -0,0 +1 @@
#include "te-pe.h"

View File

@ -0,0 +1,79 @@
/* tc.h - target cpu dependent
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 2000, 2001, 2003,
2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* In theory (mine, at least!) the machine dependent part of the assembler
should only have to include one file. This one. -- JF */
extern const pseudo_typeS md_pseudo_table[];
char * md_atof (int, char *, int *);
int md_parse_option (int, char *);
void md_show_usage (FILE *);
void md_assemble (char *);
void md_begin (void);
#ifndef md_number_to_chars
void md_number_to_chars (char *, valueT, int);
#endif
void md_apply_fix (fixS *, valueT *, segT);
#ifndef WORKING_DOT_WORD
extern int md_short_jump_size;
extern int md_long_jump_size;
#endif
#ifdef TE_PE
/* The name of an external symbol which is
used to make weak PE symbol names unique. */
extern const char * an_external_name;
#endif
#ifndef md_create_long_jump
void md_create_long_jump (char *, addressT, addressT, fragS *, symbolS *);
#endif
#ifndef md_create_short_jump
void md_create_short_jump (char *, addressT, addressT, fragS *, symbolS *);
#endif
#ifndef md_pcrel_from
long md_pcrel_from (fixS *);
#endif
#ifndef md_operand
void md_operand (expressionS *);
#endif
#ifndef md_estimate_size_before_relax
int md_estimate_size_before_relax (fragS * fragP, segT);
#endif
#ifndef md_section_align
valueT md_section_align (segT, valueT);
#endif
#ifndef md_undefined_symbol
symbolS *md_undefined_symbol (char *);
#endif
#ifndef md_convert_frag
void md_convert_frag (bfd *, segT, fragS *);
#endif
#ifndef RELOC_EXPANSION_POSSIBLE
extern arelent *tc_gen_reloc (asection *, fixS *);
#else
extern arelent **tc_gen_reloc (asection *, fixS *);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,191 @@
/* write.h
Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
2002, 2003, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS 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 3, or (at your option)
any later version.
GAS 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 GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#ifndef __write_h__
#define __write_h__
/* This is the name of a fake symbol which will never appear in the
assembler output. S_IS_LOCAL detects it because of the \001. */
#ifndef FAKE_LABEL_NAME
#define FAKE_LABEL_NAME "L0\001"
#endif
#include "bit_fix.h"
/*
* FixSs may be built up in any order.
*/
struct fix
{
/* These small fields are grouped together for compactness of
this structure, and efficiency of access on some architectures. */
/* Is this a pc-relative relocation? */
unsigned fx_pcrel : 1;
/* Is this value an immediate displacement? */
/* Only used on ns32k; merge it into TC_FIX_TYPE sometime. */
unsigned fx_im_disp : 2;
/* Some bits for the CPU specific code. */
unsigned fx_tcbit : 1;
unsigned fx_tcbit2 : 1;
/* Has this relocation already been applied? */
unsigned fx_done : 1;
/* Suppress overflow complaints on large addends. This is used
in the PowerPC ELF config to allow large addends on the
BFD_RELOC_{LO16,HI16,HI16_S} relocations.
@@ Can this be determined from BFD? */
unsigned fx_no_overflow : 1;
/* The value is signed when checking for overflow. */
unsigned fx_signed : 1;
/* pc-relative offset adjust (only used by some CPU specific code) */
signed char fx_pcrel_adjust;
/* How many bytes are involved? */
unsigned char fx_size;
/* Which frag does this fix apply to? */
fragS *fx_frag;
/* Where is the first byte to fix up? */
long fx_where;
/* NULL or Symbol whose value we add in. */
symbolS *fx_addsy;
/* NULL or Symbol whose value we subtract. */
symbolS *fx_subsy;
/* Absolute number we add in. */
valueT fx_offset;
/* The value of dot when the fixup expression was parsed. */
addressT fx_dot_value;
/* The frag fx_dot_value is based on. */
fragS *fx_dot_frag;
/* Next fixS in linked list, or NULL. */
struct fix *fx_next;
/* If NULL, no bitfix's to do. */
/* Only i960-coff and ns32k use this, and i960-coff stores an
integer. This can probably be folded into tc_fix_data, below.
@@ Alpha also uses it, but only to disable certain relocation
processing. */
bit_fixS *fx_bit_fixP;
bfd_reloc_code_real_type fx_r_type;
/* This field is sort of misnamed. It appears to be a sort of random
scratch field, for use by the back ends. The main gas code doesn't
do anything but initialize it to zero. The use of it does need to
be coordinated between the cpu and format files, though. E.g., some
coff targets pass the `addend' field from the cpu file via this
field. I don't know why the `fx_offset' field above can't be used
for that; investigate later and document. KR */
valueT fx_addnumber;
/* The location of the instruction which created the reloc, used
in error messages. */
char *fx_file;
unsigned fx_line;
#ifdef USING_CGEN
struct {
/* CGEN_INSN entry for this instruction. */
const struct cgen_insn *insn;
/* Target specific data, usually reloc number. */
int opinfo;
/* Which ifield this fixup applies to. */
struct cgen_maybe_multi_ifield * field;
/* is this field is the MSB field in a set? */
int msb_field_p;
} fx_cgen;
#endif
#ifdef TC_FIX_TYPE
/* Location where a backend can attach additional data
needed to perform fixups. */
TC_FIX_TYPE tc_fix_data;
#endif
};
typedef struct fix fixS;
struct reloc_list
{
struct reloc_list *next;
union
{
struct
{
symbolS *offset_sym;
reloc_howto_type *howto;
symbolS *sym;
bfd_vma addend;
} a;
struct
{
asection *sec;
asymbol *s;
arelent r;
} b;
} u;
char *file;
unsigned int line;
};
extern int finalize_syms;
extern symbolS *abs_section_sym;
extern addressT dot_value;
extern fragS *dot_frag;
extern struct reloc_list* reloc_list;
extern void append (char **charPP, char *fromP, unsigned long length);
extern void record_alignment (segT seg, int align);
extern int get_recorded_alignment (segT seg);
extern void subsegs_finish (void);
extern void write_object_file (void);
extern long relax_frag (segT, fragS *, long);
extern int relax_segment (struct frag *, segT, int);
extern void number_to_chars_littleendian (char *, valueT, int);
extern void number_to_chars_bigendian (char *, valueT, int);
extern fixS *fix_new
(fragS * frag, int where, int size, symbolS * add_symbol,
offsetT offset, int pcrel, bfd_reloc_code_real_type r_type);
extern fixS *fix_at_start
(fragS * frag, int size, symbolS * add_symbol,
offsetT offset, int pcrel, bfd_reloc_code_real_type r_type);
extern fixS *fix_new_exp
(fragS * frag, int where, int size, expressionS *exp, int pcrel,
bfd_reloc_code_real_type r_type);
extern void write_print_statistics (FILE *);
#endif /* __write_h__ */