1 1.1 christos # This shell script emits a C file. -*- C -*- 2 1.1.1.4 christos # Copyright (C) 2013-2025 Free Software Foundation, Inc. 3 1.1 christos # 4 1.1 christos # This file is part of GNU Binutils. 5 1.1 christos # 6 1.1 christos # This program is free software; you can redistribute it and/or modify 7 1.1 christos # it under the terms of the GNU General Public License as published by 8 1.1 christos # the Free Software Foundation; either version 3 of the License, or 9 1.1 christos # (at your option) any later version. 10 1.1 christos # 11 1.1 christos # This program is distributed in the hope that it will be useful, 12 1.1 christos # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 christos # GNU General Public License for more details. 15 1.1 christos # 16 1.1 christos # You should have received a copy of the GNU General Public License 17 1.1 christos # along with this program; if not, write to the Free Software 18 1.1 christos # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19 1.1 christos # MA 02110-1301, USA. 20 1.1 christos 21 1.1 christos # This file is sourced from elf.em, and defines extra C-SKY ELF 22 1.1 christos # specific routines. 23 1.1 christos # 24 1.1 christos fragment <<EOF 25 1.1 christos 26 1.1 christos #include "ldctor.h" 27 1.1 christos #include "elf/csky.h" 28 1.1 christos #include "elf32-csky.h" 29 1.1 christos 30 1.1 christos /* To use branch stub or not. */ 31 1.1.1.2 christos extern bool use_branch_stub; 32 1.1 christos 33 1.1 christos /* Fake input file for stubs. */ 34 1.1 christos static lang_input_statement_type *stub_file; 35 1.1 christos 36 1.1 christos /* Whether we need to call gldcsky_layout_sections_again. */ 37 1.1 christos static int need_laying_out = 0; 38 1.1 christos 39 1.1 christos /* Maximum size of a group of input sections that can be handled by 40 1.1 christos one stub section. A value of +/-1 indicates the bfd back-end 41 1.1 christos should use a suitable default size. */ 42 1.1 christos static bfd_signed_vma group_size = 1; 43 1.1 christos 44 1.1 christos struct hook_stub_info 45 1.1 christos { 46 1.1 christos lang_statement_list_type add; 47 1.1 christos asection *input_section; 48 1.1 christos }; 49 1.1 christos 50 1.1 christos /* Traverse the linker tree to find the spot where the stub goes. */ 51 1.1.1.2 christos static bool 52 1.1 christos hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp) 53 1.1 christos { 54 1.1 christos lang_statement_union_type *l; 55 1.1.1.2 christos bool ret; 56 1.1 christos 57 1.1 christos for (l = *lp; l != NULL; lp = &l->header.next, l = *lp) 58 1.1 christos switch (l->header.type) 59 1.1 christos { 60 1.1 christos case lang_constructors_statement_enum: 61 1.1 christos ret = hook_in_stub (info, &constructor_list.head); 62 1.1 christos if (ret) 63 1.1 christos return ret; 64 1.1 christos break; 65 1.1 christos 66 1.1 christos case lang_output_section_statement_enum: 67 1.1 christos ret = hook_in_stub (info, 68 1.1 christos &l->output_section_statement.children.head); 69 1.1 christos if (ret) 70 1.1 christos return ret; 71 1.1 christos break; 72 1.1 christos 73 1.1 christos case lang_wild_statement_enum: 74 1.1 christos ret = hook_in_stub (info, &l->wild_statement.children.head); 75 1.1 christos if (ret) 76 1.1 christos return ret; 77 1.1 christos break; 78 1.1 christos 79 1.1 christos case lang_group_statement_enum: 80 1.1 christos ret = hook_in_stub (info, &l->group_statement.children.head); 81 1.1 christos if (ret) 82 1.1 christos return ret; 83 1.1 christos break; 84 1.1 christos 85 1.1 christos case lang_input_section_enum: 86 1.1 christos if (l->input_section.section == info->input_section) 87 1.1 christos { 88 1.1 christos /* We've found our section. Insert the stub immediately 89 1.1 christos after its associated input section. */ 90 1.1 christos *(info->add.tail) = l->header.next; 91 1.1 christos l->header.next = info->add.head; 92 1.1.1.2 christos return true; 93 1.1 christos } 94 1.1 christos break; 95 1.1 christos 96 1.1 christos case lang_data_statement_enum: 97 1.1 christos case lang_reloc_statement_enum: 98 1.1 christos case lang_object_symbols_statement_enum: 99 1.1 christos case lang_output_statement_enum: 100 1.1 christos case lang_target_statement_enum: 101 1.1 christos case lang_input_statement_enum: 102 1.1 christos case lang_assignment_statement_enum: 103 1.1 christos case lang_padding_statement_enum: 104 1.1 christos case lang_address_statement_enum: 105 1.1 christos case lang_fill_statement_enum: 106 1.1 christos break; 107 1.1 christos 108 1.1 christos default: 109 1.1 christos FAIL (); 110 1.1 christos break; 111 1.1 christos } 112 1.1 christos 113 1.1.1.2 christos return false; 114 1.1 christos } 115 1.1 christos EOF 116 1.1 christos 117 1.1 christos case ${target} in 118 1.1 christos csky-*-linux-*) 119 1.1 christos fragment <<EOF 120 1.1 christos 121 1.1 christos static void 122 1.1 christos csky_elf_before_parse (void) 123 1.1 christos { 124 1.1.1.2 christos use_branch_stub = false; 125 1.1 christos gld${EMULATION_NAME}_before_parse (); 126 1.1 christos } 127 1.1 christos EOF 128 1.1 christos ;; 129 1.1 christos esac 130 1.1 christos 131 1.1 christos fragment <<EOF 132 1.1 christos 133 1.1 christos /* This is a convenient point to tell BFD about target specific flags. 134 1.1 christos After the output has been created, but before inputs are read. */ 135 1.1 christos static void 136 1.1 christos csky_elf_create_output_section_statements (void) 137 1.1 christos { 138 1.1 christos if (!(bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour 139 1.1 christos && elf_object_id (link_info.output_bfd) == CSKY_ELF_DATA)) 140 1.1.1.2 christos use_branch_stub = false; 141 1.1 christos 142 1.1 christos /* If don't use branch stub, just do not emit stub_file. */ 143 1.1 christos if (!use_branch_stub) 144 1.1 christos return; 145 1.1 christos 146 1.1 christos stub_file = lang_add_input_file ("linker stubs", 147 1.1 christos lang_input_file_is_fake_enum, NULL); 148 1.1 christos stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd); 149 1.1 christos if (stub_file->the_bfd == NULL 150 1.1 christos || !bfd_set_arch_mach (stub_file->the_bfd, 151 1.1 christos bfd_get_arch (link_info.output_bfd), 152 1.1 christos bfd_get_mach (link_info.output_bfd))) 153 1.1 christos { 154 1.1.1.4 christos fatal (_("%P: can not create BFD: %E\n")); 155 1.1 christos return; 156 1.1 christos } 157 1.1 christos 158 1.1 christos stub_file->the_bfd->flags |= BFD_LINKER_CREATED; 159 1.1 christos ldlang_add_file (stub_file); 160 1.1 christos } 161 1.1 christos 162 1.1 christos /* Call-back for elf32_csky_size_stubs. */ 163 1.1 christos 164 1.1 christos /* Create a new stub section, and arrange for it to be linked 165 1.1 christos immediately after INPUT_SECTION. */ 166 1.1 christos static asection * 167 1.1 christos elf32_csky_add_stub_section (const char *stub_sec_name, 168 1.1 christos asection *input_section) 169 1.1 christos { 170 1.1 christos asection *stub_sec; 171 1.1 christos flagword flags; 172 1.1 christos asection *output_section; 173 1.1 christos const char *secname; 174 1.1 christos lang_output_section_statement_type *os; 175 1.1 christos struct hook_stub_info info; 176 1.1 christos 177 1.1 christos flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE 178 1.1 christos | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP); 179 1.1 christos stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd, 180 1.1 christos stub_sec_name, flags); 181 1.1 christos if (stub_sec == NULL) 182 1.1 christos goto err_ret; 183 1.1 christos 184 1.1 christos bfd_set_section_alignment (stub_sec, 3); 185 1.1 christos 186 1.1 christos output_section = input_section->output_section; 187 1.1 christos secname = bfd_section_name (output_section); 188 1.1 christos os = lang_output_section_find (secname); 189 1.1 christos 190 1.1 christos info.input_section = input_section; 191 1.1 christos lang_list_init (&info.add); 192 1.1.1.2 christos lang_add_section (&info.add, stub_sec, NULL, NULL, os); 193 1.1 christos 194 1.1 christos if (info.add.head == NULL) 195 1.1 christos goto err_ret; 196 1.1 christos 197 1.1 christos if (hook_in_stub (&info, &os->children.head)) 198 1.1 christos return stub_sec; 199 1.1 christos 200 1.1.1.2 christos err_ret: 201 1.1 christos einfo (_("%X%P: can not make stub section: %E\n")); 202 1.1 christos return NULL; 203 1.1 christos } 204 1.1 christos 205 1.1 christos /* Another call-back for elf_csky_size_stubs. */ 206 1.1 christos static void 207 1.1 christos gldcsky_layout_sections_again (void) 208 1.1 christos { 209 1.1 christos /* If we have changed sizes of the stub sections, then we need 210 1.1 christos to recalculate all the section offsets. This may mean we need to 211 1.1 christos add even more stubs. */ 212 1.1.1.2 christos ldelf_map_segments (true); 213 1.1 christos need_laying_out = -1; 214 1.1 christos } 215 1.1 christos 216 1.1 christos static void 217 1.1 christos build_section_lists (lang_statement_union_type *statement) 218 1.1 christos { 219 1.1 christos if (statement->header.type == lang_input_section_enum) 220 1.1 christos { 221 1.1 christos asection *i = statement->input_section.section; 222 1.1 christos 223 1.1 christos if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS 224 1.1 christos && (i->flags & SEC_EXCLUDE) == 0 225 1.1 christos && i->output_section != NULL 226 1.1 christos && i->output_section->owner == link_info.output_bfd) 227 1.1 christos elf32_csky_next_input_section (&link_info, i); 228 1.1 christos } 229 1.1 christos } 230 1.1 christos 231 1.1 christos static void 232 1.1 christos gld${EMULATION_NAME}_after_allocation (void) 233 1.1 christos { 234 1.1 christos /* bfd_elf32_discard_info just plays with debugging sections, 235 1.1 christos ie. doesn't affect any code, so we can delay resizing the 236 1.1 christos sections. It's likely we'll resize everything in the process of 237 1.1 christos adding stubs. */ 238 1.1 christos if (bfd_elf_discard_info (link_info.output_bfd, &link_info)) 239 1.1 christos need_laying_out = 1; 240 1.1 christos 241 1.1 christos /* If generating a relocatable output file, then we don't 242 1.1 christos have to examine the relocs. */ 243 1.1 christos 244 1.1 christos if (stub_file != NULL && !bfd_link_relocatable (&link_info)) 245 1.1 christos { 246 1.1 christos int ret = elf32_csky_setup_section_lists (link_info.output_bfd, 247 1.1 christos &link_info); 248 1.1 christos 249 1.1 christos if (ret < 0) 250 1.1 christos { 251 1.1 christos einfo (_("%X%P: could not compute sections lists for stub generation: %E\n")); 252 1.1 christos return; 253 1.1 christos } 254 1.1 christos else if (ret != 0) 255 1.1 christos { 256 1.1 christos lang_for_each_statement (build_section_lists); 257 1.1 christos 258 1.1 christos /* Call into the BFD backend to do the real work. */ 259 1.1 christos if (! elf32_csky_size_stubs (link_info.output_bfd, 260 1.1 christos stub_file->the_bfd, 261 1.1 christos &link_info, 262 1.1 christos group_size, 263 1.1 christos &elf32_csky_add_stub_section, 264 1.1 christos &gldcsky_layout_sections_again)) 265 1.1 christos { 266 1.1 christos einfo (_("%X%P: cannot size stub section: %E\n")); 267 1.1 christos return; 268 1.1 christos } 269 1.1 christos } 270 1.1 christos } 271 1.1 christos 272 1.1 christos if (need_laying_out != -1) 273 1.1 christos ldelf_map_segments (need_laying_out); 274 1.1 christos } 275 1.1 christos 276 1.1 christos static void 277 1.1 christos gld${EMULATION_NAME}_finish (void) 278 1.1 christos { 279 1.1 christos if (stub_file != NULL 280 1.1 christos && !bfd_link_relocatable (&link_info) 281 1.1 christos && stub_file->the_bfd->sections != NULL 282 1.1 christos && !elf32_csky_build_stubs (&link_info)) 283 1.1 christos einfo (_("%X%P: cannot build stubs: %E\n")); 284 1.1 christos finish_default (); 285 1.1 christos } 286 1.1 christos 287 1.1 christos EOF 288 1.1 christos 289 1.1 christos # This code gets inserted into the generic elf32.sc linker script 290 1.1 christos # and allows us to define our own command line switches. 291 1.1 christos PARSE_AND_LIST_LONGOPTS=' 292 1.1 christos {"branch-stub", no_argument, NULL, OPTION_BRANCH_STUB}, 293 1.1 christos {"no-branch-stub", no_argument, NULL, OPTION_NO_BRANCH_STUB}, 294 1.1 christos {"stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE}, 295 1.1 christos ' 296 1.1 christos PARSE_AND_LIST_OPTIONS=' 297 1.1.1.2 christos fprintf (file, _(" --[no-]branch-stub " 298 1.1.1.2 christos "Disable/enable use of stubs to expand branch\n" 299 1.1.1.2 christos " " 300 1.1.1.2 christos " instructions that cannot reach the target.\n")); 301 1.1.1.2 christos fprintf (file, _(" --stub-group-size=N " 302 1.1.1.2 christos "Maximum size of a group of input sections\n" 303 1.1.1.2 christos " " 304 1.1.1.2 christos " handled by one stub section.\n")); 305 1.1 christos ' 306 1.1 christos 307 1.1 christos PARSE_AND_LIST_ARGS_CASES=' 308 1.1 christos case OPTION_BRANCH_STUB: 309 1.1.1.2 christos use_branch_stub = true; 310 1.1 christos break; 311 1.1 christos case OPTION_NO_BRANCH_STUB: 312 1.1.1.2 christos use_branch_stub = false; 313 1.1 christos break; 314 1.1 christos 315 1.1 christos case OPTION_STUBGROUP_SIZE: 316 1.1 christos { 317 1.1 christos const char *end; 318 1.1 christos 319 1.1 christos group_size = bfd_scan_vma (optarg, &end, 0); 320 1.1 christos if (*end) 321 1.1.1.4 christos fatal (_("%P: invalid number `%s'\''\n"), optarg); 322 1.1 christos } 323 1.1 christos break; 324 1.1 christos ' 325 1.1 christos 326 1.1 christos case ${target} in 327 1.1 christos csky-*-linux-*) LDEMUL_BEFORE_PARSE=csky_elf_before_parse ;; 328 1.1 christos esac 329 1.1 christos LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation 330 1.1 christos LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=csky_elf_create_output_section_statements 331 1.1 christos LDEMUL_FINISH=gld${EMULATION_NAME}_finish 332