xref: /netbsd-src/external/gpl3/binutils/dist/ld/emultempl/nto.em (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1# This shell script emits a C file. -*- C -*-
2#   Copyright (C) 2023-2024 Free Software Foundation, Inc.
3#
4# This file is part of GLD, the Gnu Linker.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
19#
20
21# This file is sourced from elf.em, and defines extra Neutrino
22# specific routines.
23
24# NTO templates aims to refine the default ${ARCH}elf.em template.
25. "${srcdir}/emultempl/${ARCH}elf.em"
26
27cat >>e${EMULATION_NAME}.c <<EOF
28
29#include "elf/internal.h"
30#include "elf/common.h"
31#include "elf-bfd.h"
32#include "../bfd/libbfd.h"
33
34bool nto_lazy_stack = false;
35struct nto_stack_note
36{
37  unsigned char stacksize[4];
38  unsigned char stackalloc[4];
39  unsigned char execstack[4];
40};
41
42static asection*
43nto_create_QNX_note_section(int type)
44{
45  asection *note_sec;
46  flagword flags;
47  Elf_External_Note *e_note;
48  bfd_size_type size;
49
50  /* As ${ARCH}elf.em is imported and ${ARCH}_elf_create_output_section_statements
51     is called before this function, stub_file should already be defined.  */
52  if (!stub_file)
53    {
54      einfo (_("%F%P: cannot create .note section in stub BFD.\n"));
55      return NULL;
56    }
57
58  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
59	   | SEC_IN_MEMORY | SEC_LINKER_CREATED);
60  note_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd, ".note", flags);
61  if (! note_sec)
62    {
63      einfo (_("%F%P: failed to create .note section\n"));
64      return NULL;
65    }
66
67  size = offsetof (Elf_External_Note, name[sizeof "QNX"]);
68  size = (size + 3) & -(bfd_size_type) 4;
69  size += sizeof (struct nto_stack_note);
70  note_sec->size = size;
71
72  elf_section_type (note_sec) = SHT_NOTE;
73  note_sec->contents = xmalloc (note_sec->size);
74  e_note = (Elf_External_Note *) note_sec->contents;
75  bfd_h_put_32 (stub_file->the_bfd, sizeof "QNX", &e_note->namesz);
76  bfd_h_put_32 (stub_file->the_bfd, sizeof (struct nto_stack_note), &e_note->descsz);
77  bfd_h_put_32 (stub_file->the_bfd, type, &e_note->type);
78  memcpy (e_note->name, "QNX", sizeof "QNX");
79
80  return note_sec;
81}
82
83/* Lookup for a section holding a QNX note or create a new section.  */
84static asection*
85nto_lookup_QNX_note_section(int type)
86{
87  asection *stack_note_sec = NULL;
88  bfd *abfd;
89  bool duplicated_notes_detected = false;
90  for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
91    {
92      Elf_External_Note *e_note;
93      asection *sec;
94
95      /* QNX notes are held under a note section simply named ".note".  */
96      sec = bfd_get_section_by_name (abfd, ".note");
97      if (!sec)
98	continue;
99
100      /* Verify that this is a QNX note of the expected type.  */
101      sec->contents = xmalloc(sec->size);
102      if (!bfd_get_section_contents (sec->owner, sec, sec->contents, (file_ptr) 0,
103				     sec->size))
104	einfo (_("%F%P: %pB: can't read contents of section .note: %E\n"),
105	       sec->owner);
106
107      e_note = (Elf_External_Note *) sec->contents;
108      if (! strcmp("QNX", e_note->name) && *e_note->type == type)
109	{
110	  if (stack_note_sec)
111	    {
112	      if (!duplicated_notes_detected)
113		{
114		  einfo (_("%P: %pB: warning: duplicated QNX stack .note detected\n"),
115			 stack_note_sec->owner);
116		  duplicated_notes_detected = true;
117		}
118	      einfo (_("%P: %pB: warning: duplicated QNX stack .note detected\n"),
119		     sec->owner);
120	    }
121	  else
122	    {
123	      stack_note_sec = sec;
124	      /* Allow modification of this .note content.  */
125	      stack_note_sec->flags |= SEC_IN_MEMORY;
126	    }
127	}
128    }
129
130  if (stack_note_sec)
131    return stack_note_sec;
132  else
133    return nto_create_QNX_note_section(type);
134
135}
136
137/* Generate the QNX stack .note section.  */
138static void
139nto_add_note_section (void) {
140  asection *note_sec;
141  struct nto_stack_note *n_note;
142  bfd_size_type h_size;
143  bool is_update = false;
144
145  if (nto_lazy_stack && !link_info.stacksize)
146    {
147      einfo (_("%F%P: error: --lazy-stack must follow -zstack-size=<size>\n"));
148      return;
149    }
150
151  /* Don't create a note if none of the stack parameter have to be modified.  */
152  if (link_info.stacksize <= 0 && (link_info.execstack == link_info.noexecstack))
153    return;
154
155  note_sec = nto_lookup_QNX_note_section(QNT_STACK);
156  if (! note_sec)
157    return;
158
159  /* Update QNX stack note content.  */
160  h_size = note_sec->size - sizeof(struct nto_stack_note);
161  n_note = (struct nto_stack_note *) (note_sec->contents + h_size);
162  is_update = note_sec->owner != stub_file->the_bfd;
163
164  if (link_info.stacksize > 0)
165    bfd_h_put_32 (note_sec->owner, link_info.stacksize, &n_note->stacksize);
166  else if (!is_update)
167    bfd_h_put_32 (note_sec->owner, 0, &n_note->stacksize);
168
169  if (nto_lazy_stack || (!is_update && link_info.stacksize <= 0))
170    bfd_h_put_32 (note_sec->owner, 4096, &n_note->stackalloc);
171  else if (link_info.stacksize > 0)
172    bfd_h_put_32 (note_sec->owner, link_info.stacksize, &n_note->stackalloc);
173
174  if (link_info.execstack)
175    bfd_h_put_32 (note_sec->owner, 0, &n_note->execstack);
176  else if (!is_update || link_info.noexecstack)
177    bfd_h_put_32 (note_sec->owner, 1, &n_note->execstack);
178}
179
180static void
181nto_after_open (void)
182{
183  nto_add_note_section();
184  gld${EMULATION_NAME}_after_open ();
185}
186
187EOF
188
189# Define some shell vars to insert bits of code into the standard elf
190# parse_args and list_options functions.
191#
192
193PARSE_AND_LIST_PROLOGUE=${PARSE_AND_LIST_PROLOGUE}'
194enum nto_options
195{
196  OPTION_STACK = 500,
197  OPTION_LAZY_STACK,
198};
199'
200
201PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
202  { "stack", required_argument, NULL, OPTION_STACK },
203  { "lazy-stack", no_argument, NULL, OPTION_LAZY_STACK },
204'
205
206PARSE_AND_LIST_OPTIONS=${PARSE_AND_LIST_OPTIONS}'
207  fprintf (file, _("\
208  --stack <size>              Set size of the initial stack\n\
209  --lazy-stack		      Set lazy allocation of stack\n\
210"));
211'
212
213PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
214    case OPTION_STACK:
215      {
216        char *end;
217        link_info.stacksize = strtoul (optarg, &end, 0);
218        if (*end || link_info.stacksize < 0)
219          einfo (_("%F%P: invalid stack size `%s'\''\n"), optarg + 11);
220        if (!link_info.stacksize)
221          /* Use -1 for explicit no-stack, because zero means
222             'default'.   */
223          link_info.stacksize = -1;
224        break;
225      }
226    case OPTION_LAZY_STACK:
227      nto_lazy_stack = true;
228      break;
229'
230
231# Put these extra Neutrino routines in ld_${EMULATION_NAME}_emulation
232#
233
234LDEMUL_AFTER_OPEN=nto_after_open
235