2010-04-09 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Fri, 9 Apr 2010 17:32:58 +0000 (17:32 +0000)
committerDoug Kwan <dougkwan@google.com>
Fri, 9 Apr 2010 17:32:58 +0000 (17:32 +0000)
* layout.cc (Layout::choose_output_section): Handle script section
types.
(Layout::make_output_section_for_script): Add section type parameter.
Handle script section types.
* layout.h (Layout::make_output_section_for_script): Add section
type parameter.
* output.cc (Output_section::Output_section): Initialize data member
is_noload_.
(Output_section::do_reset_address_and_file_offset): Do not set address
to 0 if section is a NOLOAD section.
* output.h (Output_section::is_noload): New method.
(Output_section::set_is_noload): Ditto.
(Output_section::is_noload_): New data member.
* script-c.h (Script_section_type): New enum type.
(struct Parser_output_section_header): Add new file section_type.
* script-sections.cc (Sections_element::output_section_name): Add
parameter for returning script section type.
(Output_section_definition::output_section_name): Ditto.
(Output_section_definition::section_type)P; New method.
(Output_section_definiton::script_section_type_name): Ditto.
(Output_section_definition::script_section_type_): New data member.
(Output_section_definition::Output_section_definition): Initialize
data member Output_section_definition::script_section_type_.
(Output_section_definition::create_sections): Pass script section type
to Layout::make_output_section_for_script.
(Output_section_definition::output_section_name): Return script
section type to caller.
(Output_section_definition::set_section_address): Do not advance
dot value and load address if section type is NOLOAD.  Set address
of NOLOAD sections regardless of section flags.
(Output_section_definition::print): Print section type if it is
not SCRIPT_SECTION_TYPE_NONE.
(Output_section_definition::section_type): New method.
(Output_section_definition::script_section_type_name): Ditto.
(Script_sections::output_section_name): Add new parameter
PSECTION_TYPE for returning script section type.  Pass it to
section elements.  Handle discard sections.
(Sort_output_sections::operator()): Handle NOLOAD sections.
* script-sections.h (Script_sections::Section_type): New enum type.
    (Script_sections::output_section_name): Add a new parameter for
returning script section type.
* script.cc (script_keyword_parsecodes): Add keywords COPY, DSECT,
INFO and NOLOAD.
* yyscript.y (union): Add new field SECTION_TYPE.
(COPY, DSECT, INFO, NOLOAD): New tokens.
(opt_address_and_section_type): Change type to output_section_header.
(section_type): New non-terminal
(section_header): Handle section type.
  (opt_address_and_section_type): Return section type value.

gold/layout.cc
gold/layout.h
gold/output.cc
gold/output.h
gold/script-c.h
gold/script-sections.cc
gold/script-sections.h
gold/script.cc
gold/yyscript.y

index f95813bd34d91d440f25b607d7ce29df5c4249bc..2ffbdf49770288e42a7cb2ab9c0825adaf260e56 100644 (file)
@@ -502,13 +502,27 @@ Layout::choose_output_section(const Relobj* relobj, const char* name,
       Script_sections* ss = this->script_options_->script_sections();
       const char* file_name = relobj == NULL ? NULL : relobj->name().c_str();
       Output_section** output_section_slot;
-      name = ss->output_section_name(file_name, name, &output_section_slot);
+      Script_sections::Section_type script_section_type;
+      name = ss->output_section_name(file_name, name, &output_section_slot,
+                                    &script_section_type);
       if (name == NULL)
        {
          // The SECTIONS clause says to discard this input section.
          return NULL;
        }
 
+      // We can only handle script section types ST_NONE and ST_NOLOAD.
+      switch (script_section_type)
+       {
+       case Script_sections::ST_NONE:
+         break;
+       case Script_sections::ST_NOLOAD:
+         flags &= elfcpp::SHF_ALLOC;
+         break;
+       default:
+         gold_unreachable();
+       }
+
       // If this is an orphan section--one not mentioned in the linker
       // script--then OUTPUT_SECTION_SLOT will be NULL, and we do the
       // default processing below.
@@ -533,6 +547,25 @@ Layout::choose_output_section(const Relobj* relobj, const char* name,
                                      is_dynamic_linker_section, is_relro,
                                      is_last_relro, is_first_non_relro);
          os->set_found_in_sections_clause();
+
+         // Special handling for NOLOAD sections.
+         if (script_section_type == Script_sections::ST_NOLOAD)
+           {
+             os->set_is_noload();
+
+             // The constructor of Output_section sets addresses of non-ALLOC
+             // sections to 0 by default.  We don't want that for NOLOAD
+             // sections even if they have no SHF_ALLOC flag.
+             if ((os->flags() & elfcpp::SHF_ALLOC) == 0
+                 && os->is_address_valid())
+               {
+                 gold_assert(os->address() == 0
+                             && !os->is_offset_valid()
+                             && !os->is_data_size_valid());
+                 os->reset_address_and_file_offset();
+               }
+           }
+
          *output_section_slot = os;
          return os;
        }
@@ -1157,13 +1190,20 @@ Layout::attach_allocated_section_to_segment(Output_section* os)
 // Make an output section for a script.
 
 Output_section*
-Layout::make_output_section_for_script(const char* name)
+Layout::make_output_section_for_script(
+    const char* name,
+    Script_sections::Section_type section_type)
 {
   name = this->namepool_.add(name, false, NULL);
+  elfcpp::Elf_Xword sh_flags = elfcpp::SHF_ALLOC;
+  if (section_type == Script_sections::ST_NOLOAD)
+    sh_flags = 0;
   Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS,
-                                                elfcpp::SHF_ALLOC, false,
+                                                sh_flags, false,
                                                 false, false, false, false);
   os->set_found_in_sections_clause();
+  if (section_type == Script_sections::ST_NOLOAD)
+    os->set_is_noload();
   return os;
 }
 
index cd15c983e8b46a1c31f6776dbb29dbd8c8dde589..912be31e15490d604c343b232d8678ce42241ecf 100644 (file)
@@ -600,7 +600,8 @@ class Layout
 
   // Make a section for a linker script to hold data.
   Output_section*
-  make_output_section_for_script(const char* name);
+  make_output_section_for_script(const char* name,
+                                Script_sections::Section_type section_type);
 
   // Make a segment.  This is used by the linker script code.
   Output_segment*
index 37ec8b3c3f7502f4aeda06f55621e896a7a96ed3..687803479a020f9b102c67b298bd7b7f62bb8bb9 100644 (file)
@@ -1911,6 +1911,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     generate_code_fills_at_write_(false),
     is_entsize_zero_(false),
     section_offsets_need_adjustment_(false),
+    is_noload_(false),
     tls_offset_(0),
     checkpoint_(NULL),
     merge_section_map_(),
@@ -2588,8 +2589,9 @@ Output_section::do_reset_address_and_file_offset()
 {
   // An unallocated section has no address.  Forcing this means that
   // we don't need special treatment for symbols defined in debug
-  // sections.  We do the same in the constructor.
-  if ((this->flags_ & elfcpp::SHF_ALLOC) == 0)
+  // sections.  We do the same in the constructor.  This does not
+  // apply to NOLOAD sections though.
+  if (((this->flags_ & elfcpp::SHF_ALLOC) == 0) && !this->is_noload_)
      this->set_address(0);
 
   for (Input_section_list::iterator p = this->input_sections_.begin();
index a63f07c1a0c13241e6985268d63f5ae4c6db8e91..808856534928bf057e19333f319a5ba605908d21 100644 (file)
@@ -2894,6 +2894,16 @@ class Output_section : public Output_data
   void
   adjust_section_offsets();
 
+  // Whether this is a NOLOAD section.
+  bool
+  is_noload() const
+  { return this->is_noload_; }
+
+  // Set NOLOAD flag.
+  void
+  set_is_noload()
+  { this->is_noload_ = true; }
+
   // Print merge statistics to stderr.
   void
   print_merge_stats();
@@ -3659,6 +3669,8 @@ class Output_section : public Output_data
   bool is_entsize_zero_ : 1;
   // Whether section offsets need adjustment due to relaxation.
   bool section_offsets_need_adjustment_ : 1;
+  // Whether this is a NOLOAD section.
+  bool is_noload_ : 1;
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;
index a646bdadf873dcc656291657bf0354d6e160020d..77b4aa410b54b5b94f395c2269f5e5c18942e171 100644 (file)
@@ -61,6 +61,18 @@ typedef Expression* Expression_ptr;
 typedef void* Expression_ptr;
 #endif
 
+/* Script_section type.  */
+enum Script_section_type
+{
+  /* No section type.  */
+  SCRIPT_SECTION_TYPE_NONE,
+  SCRIPT_SECTION_TYPE_NOLOAD,
+  SCRIPT_SECTION_TYPE_DSECT,
+  SCRIPT_SECTION_TYPE_COPY,
+  SCRIPT_SECTION_TYPE_INFO,
+  SCRIPT_SECTION_TYPE_OVERLAY
+};
+
 /* A constraint for whether to use a particular output section
    definition.  */
 
@@ -83,6 +95,8 @@ struct Parser_output_section_header
 {
   /* The address.  This may be NULL.  */
   Expression_ptr address;
+  /* Section type.  May be NULL string.  */ 
+  enum Script_section_type section_type;
   /* The load address, from the AT specifier.  This may be NULL.  */
   Expression_ptr load_address;
   /* The alignment, from the ALIGN specifier.  This may be NULL.  */
index 12a934b5b550a5683e2a1abf0768ef9337561b57..24b9103f9217d8c543c606704091902540836c53 100644 (file)
@@ -356,7 +356,8 @@ class Sections_element
   // section name.  This only real implementation is in
   // Output_section_definition.
   virtual const char*
-  output_section_name(const char*, const char*, Output_section***)
+  output_section_name(const char*, const char*, Output_section***,
+                     Script_sections::Section_type*)
   { return NULL; }
 
   // Initialize OSP with an output section.
@@ -1617,7 +1618,7 @@ class Output_section_definition : public Sections_element
   // section name.
   const char*
   output_section_name(const char* file_name, const char* section_name,
-                     Output_section***);
+                     Output_section***, Script_sections::Section_type*);
 
   // Initialize OSP with an output section.
   void
@@ -1665,7 +1666,14 @@ class Output_section_definition : public Sections_element
   void
   print(FILE*) const;
 
+  // Return the output section type if specified or Script_sections::ST_NONE.
+  Script_sections::Section_type
+  section_type() const;
+
  private:
+  static const char*
+  script_section_type_name(Script_section_type);
+
   typedef std::vector<Output_section_element*> Output_section_elements;
 
   // The output section name.
@@ -1698,6 +1706,8 @@ class Output_section_definition : public Sections_element
   uint64_t evaluated_addralign_;
   // The output section is relro.
   bool is_relro_;
+  // The output section type if specified.
+  enum Script_section_type script_section_type_;
 };
 
 // Constructor.
@@ -1719,7 +1729,8 @@ Output_section_definition::Output_section_definition(
     evaluated_address_(0),
     evaluated_load_address_(0),
     evaluated_addralign_(0),
-    is_relro_(false)
+    is_relro_(false),
+    script_section_type_(header->section_type)
 {
 }
 
@@ -1815,7 +1826,8 @@ Output_section_definition::create_sections(Layout* layout)
       if ((*p)->needs_output_section())
        {
          const char* name = this->name_.c_str();
-         this->output_section_ = layout->make_output_section_for_script(name);
+         this->output_section_ =
+           layout->make_output_section_for_script(name, this->section_type());
          return;
        }
     }
@@ -1873,9 +1885,11 @@ Output_section_definition::finalize_symbols(Symbol_table* symtab,
 // Return the output section name to use for an input section name.
 
 const char*
-Output_section_definition::output_section_name(const char* file_name,
-                                              const char* section_name,
-                                              Output_section*** slot)
+Output_section_definition::output_section_name(
+    const char* file_name,
+    const char* section_name,
+    Output_section*** slot,
+    Script_sections::Section_type *psection_type)
 {
   // Ask each element whether it matches NAME.
   for (Output_section_elements::const_iterator p = this->elements_.begin();
@@ -1887,6 +1901,7 @@ Output_section_definition::output_section_name(const char* file_name,
          // We found a match for NAME, which means that it should go
          // into this output section.
          *slot = &this->output_section_;
+         *psection_type = this->section_type();
          return this->name_.c_str();
        }
     }
@@ -1906,6 +1921,9 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
                                                  uint64_t* load_address)
 {
   uint64_t address;
+  uint64_t old_dot_value = *dot_value;
+  uint64_t old_load_address = *load_address;
+
   if (this->address_ == NULL)
     address = *dot_value;
   else
@@ -1941,10 +1959,11 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
 
   *dot_value = address;
 
-  // The address of non-SHF_ALLOC sections is forced to zero,
-  // regardless of what the linker script wants.
+  // Except for NOLOAD sections, the address of non-SHF_ALLOC sections is
+  // forced to zero, regardless of what the linker script wants.
   if (this->output_section_ != NULL
-      && (this->output_section_->flags() & elfcpp::SHF_ALLOC) != 0)
+      && ((this->output_section_->flags() & elfcpp::SHF_ALLOC) != 0
+         || this->output_section_->is_noload()))
     this->output_section_->set_address(address);
 
   this->evaluated_address_ = address;
@@ -2029,6 +2048,13 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
        this->output_section_->set_is_relro();
       else
        this->output_section_->clear_is_relro();
+
+      // If this is a NOLOAD section, keep dot and load address unchanged.
+      if (this->output_section_->is_noload())
+       {
+         *dot_value = old_dot_value;
+         *load_address = old_load_address;
+       }
     }
 }
 
@@ -2186,6 +2212,10 @@ Output_section_definition::print(FILE* f) const
       fprintf(f, " ");
     }
 
+  if (this->script_section_type_ != SCRIPT_SECTION_TYPE_NONE)
+      fprintf(f, "(%s) ",
+             this->script_section_type_name(this->script_section_type_));
+
   fprintf(f, ": ");
 
   if (this->load_address_ != NULL)
@@ -2235,6 +2265,52 @@ Output_section_definition::print(FILE* f) const
   fprintf(f, "\n");
 }
 
+Script_sections::Section_type
+Output_section_definition::section_type() const
+{
+  switch (this->script_section_type_)
+    {
+    case SCRIPT_SECTION_TYPE_NONE:
+      return Script_sections::ST_NONE;
+    case SCRIPT_SECTION_TYPE_NOLOAD:
+      return Script_sections::ST_NOLOAD;
+    case SCRIPT_SECTION_TYPE_COPY:
+    case SCRIPT_SECTION_TYPE_DSECT:
+    case SCRIPT_SECTION_TYPE_INFO:
+    case SCRIPT_SECTION_TYPE_OVERLAY:
+      // There are not really support so we treat them as ST_NONE.  The
+      // parse should have issued errors for them already.
+      return Script_sections::ST_NONE;
+    default:
+      gold_unreachable();
+    }
+}
+
+// Return the name of a script section type.
+
+const char*
+Output_section_definition::script_section_type_name (
+    Script_section_type script_section_type)
+{
+  switch (script_section_type)
+    {
+    case SCRIPT_SECTION_TYPE_NONE:
+      return "NONE";
+    case SCRIPT_SECTION_TYPE_NOLOAD:
+      return "NOLOAD";
+    case SCRIPT_SECTION_TYPE_DSECT:
+      return "DSECT";
+    case SCRIPT_SECTION_TYPE_COPY:
+      return "COPY";
+    case SCRIPT_SECTION_TYPE_INFO:
+      return "INFO";
+    case SCRIPT_SECTION_TYPE_OVERLAY:
+      return "OVERLAY";
+    default:
+      gold_unreachable();
+    }
+}
+
 // An output section created to hold orphaned input sections.  These
 // do not actually appear in linker scripts.  However, for convenience
 // when setting the output section addresses, we put a marker to these
@@ -2724,16 +2800,19 @@ Script_sections::finalize_symbols(Symbol_table* symtab, const Layout* layout)
 // and section name.
 
 const char*
-Script_sections::output_section_name(const char* file_name,
-                                    const char* section_name,
-                                    Output_section*** output_section_slot)
+Script_sections::output_section_name(
+    const char* file_name,
+    const char* section_name,
+    Output_section*** output_section_slot,
+    Script_sections::Section_type *psection_type)
 {
   for (Sections_elements::const_iterator p = this->sections_elements_->begin();
        p != this->sections_elements_->end();
        ++p)
     {
       const char* ret = (*p)->output_section_name(file_name, section_name,
-                                                 output_section_slot);
+                                                 output_section_slot,
+                                                 psection_type);
 
       if (ret != NULL)
        {
@@ -2742,6 +2821,7 @@ Script_sections::output_section_name(const char* file_name,
          if (strcmp(ret, "/DISCARD/") == 0)
            {
              *output_section_slot = NULL;
+             *psection_type = Script_sections::ST_NONE;
              return NULL;
            }
          return ret;
@@ -2752,6 +2832,7 @@ Script_sections::output_section_name(const char* file_name,
   // gets the name of the input section.
 
   *output_section_slot = NULL;
+  *psection_type = Script_sections::ST_NONE;
 
   return section_name;
 }
@@ -2967,6 +3048,12 @@ Sort_output_sections::operator()(const Output_section* os1,
   if (os1->type() == elfcpp::SHT_NOBITS && os2->type() == elfcpp::SHT_PROGBITS)
     return false;
 
+  // Sort non-NOLOAD before NOLOAD.
+  if (os1->is_noload() && !os2->is_noload())
+    return true;
+  if (!os1->is_noload() && os2->is_noload())
+    return true;
+  
   // Otherwise we don't care.
   return false;
 }
index c0d1d081c24e21c63574c4a3c9db693a78f6d7a8..725d1a2ecca753409b4b1a2ec38599fa5f3156f4 100644 (file)
@@ -52,6 +52,20 @@ class Script_sections
   typedef std::list<Sections_element*> Sections_elements;
 
  public:
+
+  // Logical script section types.  We map section types returned by the
+  // parser into these since some section types have the same semantics.
+  enum Section_type
+  {
+    // No section type specified.
+    ST_NONE,
+    // Section is NOLOAD.  We allocate space in the output but section
+    // is not loaded in runtime.
+    ST_NOLOAD,
+    // No space is allocated to section.
+    ST_NOALLOC
+  };
+
   Script_sections();
 
   // Start a SECTIONS clause.
@@ -147,9 +161,13 @@ class Script_sections
   // 3) If the input section is not mapped by the SECTIONS clause,
   //    this returns SECTION_NAME, and sets *OUTPUT_SECTION_SLOT to
   //    NULL.
+  // PSCRIPT_SECTION_TYPE points to a location for returning the section
+  // type specified in script.  This can be SCRIPT_SECTION_TYPE_NONE if
+  // no type is specified.
   const char*
   output_section_name(const char* file_name, const char* section_name,
-                     Output_section*** output_section_slot);
+                     Output_section*** output_section_slot,
+                     Section_type* pscript_section_type);
 
   // Place a marker for an orphan output section into the SECTIONS
   // clause.
index bef0cdbe30b6bee6967a27d452ca16751a479681..11e4612905c4ba837d63a92418163d82c6a251ff 100644 (file)
@@ -1646,11 +1646,13 @@ script_keyword_parsecodes[] =
   { "BYTE", BYTE },
   { "CONSTANT", CONSTANT },
   { "CONSTRUCTORS", CONSTRUCTORS },
+  { "COPY", COPY },
   { "CREATE_OBJECT_SYMBOLS", CREATE_OBJECT_SYMBOLS },
   { "DATA_SEGMENT_ALIGN", DATA_SEGMENT_ALIGN },
   { "DATA_SEGMENT_END", DATA_SEGMENT_END },
   { "DATA_SEGMENT_RELRO_END", DATA_SEGMENT_RELRO_END },
   { "DEFINED", DEFINED },
+  { "DSECT", DSECT },
   { "ENTRY", ENTRY },
   { "EXCLUDE_FILE", EXCLUDE_FILE },
   { "EXTERN", EXTERN },
@@ -1660,6 +1662,7 @@ script_keyword_parsecodes[] =
   { "GROUP", GROUP },
   { "HLL", HLL },
   { "INCLUDE", INCLUDE },
+  { "INFO", INFO },
   { "INHIBIT_COMMON_ALLOCATION", INHIBIT_COMMON_ALLOCATION },
   { "INPUT", INPUT },
   { "KEEP", KEEP },
@@ -1673,6 +1676,7 @@ script_keyword_parsecodes[] =
   { "NEXT", NEXT },
   { "NOCROSSREFS", NOCROSSREFS },
   { "NOFLOAT", NOFLOAT },
+  { "NOLOAD", NOLOAD },
   { "ONLY_IF_RO", ONLY_IF_RO },
   { "ONLY_IF_RW", ONLY_IF_RW },
   { "OPTION", OPTION },
index 81c136ae01cf184f3b735225e84cc1e34bf9ccc3..f762536c71360e23d0e0e8aee02126764d67a9b9 100644 (file)
@@ -77,6 +77,7 @@
   struct Version_dependency_list* deplist;
   struct Version_expression_list* versyms;
   struct Version_tree* versnode;
+  enum Script_section_type section_type;
 }
 
 /* Operators, including a precedence table for expressions.  */
 %token BYTE
 %token CONSTANT
 %token CONSTRUCTORS
+%token COPY
 %token CREATE_OBJECT_SYMBOLS
 %token DATA_SEGMENT_ALIGN
 %token DATA_SEGMENT_END
 %token DATA_SEGMENT_RELRO_END
 %token DEFINED
+%token DSECT
 %token ENTRY
 %token EXCLUDE_FILE
 %token EXTERN
 %token HLL
 %token INCLUDE
 %token INHIBIT_COMMON_ALLOCATION
+%token INFO
 %token INPUT
 %token KEEP
 %token LENGTH          /* LENGTH, l, len */
 %token NEXT
 %token NOCROSSREFS
 %token NOFLOAT
+%token NOLOAD
 %token ONLY_IF_RO
 %token ONLY_IF_RW
 %token ORIGIN          /* ORIGIN, o, org */
 
 /* Non-terminal types, where needed.  */
 
-%type <expr> parse_exp exp opt_address_and_section_type
+%type <expr> parse_exp exp
 %type <expr> opt_at opt_align opt_subalign opt_fill
-%type <output_section_header> section_header
+%type <output_section_header> section_header opt_address_and_section_type
+%type <section_type> section_type
 %type <output_section_trailer> section_trailer
 %type <constraint> opt_constraint
 %type <string_list> opt_phdr
@@ -343,7 +349,8 @@ section_header:
            { script_pop_lex_mode(closure); }
          opt_constraint
            {
-             $$.address = $2;
+             $$.address = $2.address;
+             $$.section_type = $2.section_type;
              $$.load_address = $3;
              $$.align = $4;
              $$.subalign = $5;
@@ -356,18 +363,61 @@ section_header:
    '(' in section_header.  */
 
 opt_address_and_section_type:
-         ':'
-           { $$ = NULL; }
+       ':'
+           {
+             $$.address = NULL;
+             $$.section_type = SCRIPT_SECTION_TYPE_NONE;
+           }
        | '(' ')' ':'
-           { $$ = NULL; }
+           {
+             $$.address = NULL;
+             $$.section_type = SCRIPT_SECTION_TYPE_NONE;
+           }
        | exp ':'
-           { $$ = $1; }
+           {
+             $$.address = $1;
+             $$.section_type = SCRIPT_SECTION_TYPE_NONE;
+           }
        | exp '(' ')' ':'
-           { $$ = $1; }
-       | exp '(' string ')' ':'
            {
-             yyerror(closure, "section types are not supported");
-             $$ = $1;
+             $$.address = $1;
+             $$.section_type = SCRIPT_SECTION_TYPE_NONE;
+           }
+       | '(' section_type ')' ':'
+           {
+             $$.address = NULL;
+             $$.section_type = $2;
+           }
+       | exp '(' section_type ')' ':'
+           {
+             $$.address = $1;
+             $$.section_type = $3;
+           }
+       ;
+
+/* We only support NOLOAD.  */
+section_type:
+       NOLOAD
+           { $$ = SCRIPT_SECTION_TYPE_NOLOAD; }
+       | DSECT
+           {
+             yyerror(closure, "DSECT section type is unsupported");
+             $$ = SCRIPT_SECTION_TYPE_DSECT;
+           }
+       | COPY
+           {
+             yyerror(closure, "COPY section type is unsupported");
+             $$ = SCRIPT_SECTION_TYPE_COPY;
+           }
+       | INFO
+           {
+             yyerror(closure, "INFO section type is unsupported");
+             $$ = SCRIPT_SECTION_TYPE_INFO;
+           }
+       | OVERLAY
+           {
+             yyerror(closure, "OVERLAY section type is unsupported");
+             $$ = SCRIPT_SECTION_TYPE_OVERLAY;
            }
        ;