| 1 | # This shell script emits a C file. -*- C -*- |
| 2 | # Copyright (C) 2011-2020 Free Software Foundation, Inc. |
| 3 | # |
| 4 | # This file is part of the GNU Binutils. |
| 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 3 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, |
| 19 | # MA 02110-1301, USA. |
| 20 | # |
| 21 | |
| 22 | # This file is sourced from elf.em, and defines extra C6X DSBT specific |
| 23 | # features. |
| 24 | # |
| 25 | fragment <<EOF |
| 26 | #include "ldctor.h" |
| 27 | #include "elf32-tic6x.h" |
| 28 | |
| 29 | static struct elf32_tic6x_params params = |
| 30 | { |
| 31 | 0, 64 |
| 32 | }; |
| 33 | |
| 34 | static int merge_exidx_entries = -1; |
| 35 | |
| 36 | static int |
| 37 | is_tic6x_target (void) |
| 38 | { |
| 39 | extern const bfd_target tic6x_elf32_le_vec; |
| 40 | extern const bfd_target tic6x_elf32_be_vec; |
| 41 | extern const bfd_target tic6x_elf32_linux_le_vec; |
| 42 | extern const bfd_target tic6x_elf32_linux_be_vec; |
| 43 | extern const bfd_target tic6x_elf32_c6000_le_vec; |
| 44 | extern const bfd_target tic6x_elf32_c6000_be_vec; |
| 45 | |
| 46 | return (link_info.output_bfd->xvec == &tic6x_elf32_le_vec |
| 47 | || link_info.output_bfd->xvec == &tic6x_elf32_be_vec |
| 48 | || link_info.output_bfd->xvec == &tic6x_elf32_linux_le_vec |
| 49 | || link_info.output_bfd->xvec == &tic6x_elf32_linux_be_vec |
| 50 | || link_info.output_bfd->xvec == &tic6x_elf32_c6000_le_vec |
| 51 | || link_info.output_bfd->xvec == &tic6x_elf32_c6000_be_vec); |
| 52 | } |
| 53 | |
| 54 | /* Pass params to backend. */ |
| 55 | |
| 56 | static void |
| 57 | tic6x_after_open (void) |
| 58 | { |
| 59 | if (is_tic6x_target ()) |
| 60 | { |
| 61 | if (params.dsbt_index >= params.dsbt_size) |
| 62 | { |
| 63 | einfo (_("%F%P: invalid --dsbt-index %d, outside DSBT size\n"), |
| 64 | params.dsbt_index); |
| 65 | } |
| 66 | elf32_tic6x_setup (&link_info, ¶ms); |
| 67 | } |
| 68 | |
| 69 | gld${EMULATION_NAME}_after_open (); |
| 70 | } |
| 71 | |
| 72 | static int |
| 73 | compare_output_sec_vma (const void *a, const void *b) |
| 74 | { |
| 75 | asection *asec = *(asection **) a, *bsec = *(asection **) b; |
| 76 | asection *aout = asec->output_section, *bout = bsec->output_section; |
| 77 | bfd_vma avma, bvma; |
| 78 | |
| 79 | /* If there's no output section for some reason, compare equal. */ |
| 80 | if (!aout || !bout) |
| 81 | return 0; |
| 82 | |
| 83 | avma = aout->vma + asec->output_offset; |
| 84 | bvma = bout->vma + bsec->output_offset; |
| 85 | |
| 86 | if (avma > bvma) |
| 87 | return 1; |
| 88 | else if (avma < bvma) |
| 89 | return -1; |
| 90 | |
| 91 | return 0; |
| 92 | } |
| 93 | |
| 94 | static void |
| 95 | gld${EMULATION_NAME}_after_allocation (void) |
| 96 | { |
| 97 | int layout_changed = 0; |
| 98 | int ret; |
| 99 | |
| 100 | if (!bfd_link_relocatable (&link_info)) |
| 101 | { |
| 102 | /* Build a sorted list of input text sections, then use that to process |
| 103 | the unwind table index. */ |
| 104 | unsigned int list_size = 10; |
| 105 | asection **sec_list = (asection **) |
| 106 | xmalloc (list_size * sizeof (asection *)); |
| 107 | unsigned int sec_count = 0; |
| 108 | |
| 109 | LANG_FOR_EACH_INPUT_STATEMENT (is) |
| 110 | { |
| 111 | bfd *abfd = is->the_bfd; |
| 112 | asection *sec; |
| 113 | |
| 114 | if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) |
| 115 | continue; |
| 116 | |
| 117 | for (sec = abfd->sections; sec != NULL; sec = sec->next) |
| 118 | { |
| 119 | asection *out_sec = sec->output_section; |
| 120 | |
| 121 | if (out_sec |
| 122 | && elf_section_data (sec) |
| 123 | && elf_section_type (sec) == SHT_PROGBITS |
| 124 | && (elf_section_flags (sec) & SHF_EXECINSTR) != 0 |
| 125 | && (sec->flags & SEC_EXCLUDE) == 0 |
| 126 | && sec->sec_info_type != SEC_INFO_TYPE_JUST_SYMS |
| 127 | && out_sec != bfd_abs_section_ptr) |
| 128 | { |
| 129 | if (sec_count == list_size) |
| 130 | { |
| 131 | list_size *= 2; |
| 132 | sec_list = (asection **) |
| 133 | xrealloc (sec_list, list_size * sizeof (asection *)); |
| 134 | } |
| 135 | |
| 136 | sec_list[sec_count++] = sec; |
| 137 | } |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | qsort (sec_list, sec_count, sizeof (asection *), &compare_output_sec_vma); |
| 142 | |
| 143 | if (elf32_tic6x_fix_exidx_coverage (sec_list, sec_count, &link_info, |
| 144 | merge_exidx_entries)) |
| 145 | layout_changed = 1; |
| 146 | |
| 147 | free (sec_list); |
| 148 | } |
| 149 | |
| 150 | /* bfd_elf32_discard_info just plays with debugging sections, |
| 151 | ie. doesn't affect any code, so we can delay resizing the |
| 152 | sections. */ |
| 153 | ret = bfd_elf_discard_info (link_info.output_bfd, & link_info); |
| 154 | if (ret < 0) |
| 155 | { |
| 156 | einfo (_("%X%P: .eh_frame/.stab edit: %E\n")); |
| 157 | return; |
| 158 | } |
| 159 | else if (ret > 0) |
| 160 | layout_changed = 1; |
| 161 | |
| 162 | ldelf_map_segments (layout_changed); |
| 163 | } |
| 164 | EOF |
| 165 | |
| 166 | # This code gets inserted into the generic elf32.sc linker script |
| 167 | # and allows us to define our own command line switches. |
| 168 | PARSE_AND_LIST_PROLOGUE=' |
| 169 | #define OPTION_DSBT_INDEX 300 |
| 170 | #define OPTION_DSBT_SIZE 301 |
| 171 | #define OPTION_NO_MERGE_EXIDX_ENTRIES 302 |
| 172 | ' |
| 173 | |
| 174 | PARSE_AND_LIST_LONGOPTS=' |
| 175 | {"dsbt-index", required_argument, NULL, OPTION_DSBT_INDEX}, |
| 176 | {"dsbt-size", required_argument, NULL, OPTION_DSBT_SIZE}, |
| 177 | { "no-merge-exidx-entries", no_argument, NULL, OPTION_NO_MERGE_EXIDX_ENTRIES }, |
| 178 | ' |
| 179 | |
| 180 | PARSE_AND_LIST_OPTIONS=' |
| 181 | fprintf (file, _(" --dsbt-index <index> Use this as the DSBT index for the output object\n")); |
| 182 | fprintf (file, _(" --dsbt-size <index> Use this as the number of entries in the DSBT table\n")); |
| 183 | fprintf (file, _(" --no-merge-exidx-entries\n")); |
| 184 | fprintf (file, _(" Disable merging exidx entries\n")); |
| 185 | ' |
| 186 | |
| 187 | PARSE_AND_LIST_ARGS_CASES=' |
| 188 | case OPTION_DSBT_INDEX: |
| 189 | { |
| 190 | char *end; |
| 191 | params.dsbt_index = strtol (optarg, &end, 0); |
| 192 | if (*end == 0 |
| 193 | && params.dsbt_index >= 0 && params.dsbt_index < 0x7fff) |
| 194 | break; |
| 195 | einfo (_("%F%P: invalid --dsbt-index %s\n"), optarg); |
| 196 | } |
| 197 | break; |
| 198 | case OPTION_DSBT_SIZE: |
| 199 | { |
| 200 | char *end; |
| 201 | params.dsbt_size = strtol (optarg, &end, 0); |
| 202 | if (*end == 0 |
| 203 | && params.dsbt_size >= 0 && params.dsbt_size < 0x7fff) |
| 204 | break; |
| 205 | einfo (_("%F%P: invalid --dsbt-size %s\n"), optarg); |
| 206 | } |
| 207 | break; |
| 208 | case OPTION_NO_MERGE_EXIDX_ENTRIES: |
| 209 | merge_exidx_entries = 0; |
| 210 | ' |
| 211 | |
| 212 | LDEMUL_AFTER_OPEN=tic6x_after_open |
| 213 | LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation |