linux/tools/objtool/elf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * elf.c - ELF access library
   4 *
   5 * Adapted from kpatch (https://github.com/dynup/kpatch):
   6 * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com>
   7 * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
   8 */
   9
  10#include <sys/types.h>
  11#include <sys/stat.h>
  12#include <fcntl.h>
  13#include <stdio.h>
  14#include <stdlib.h>
  15#include <string.h>
  16#include <unistd.h>
  17#include <errno.h>
  18#include "builtin.h"
  19
  20#include "elf.h"
  21#include "warn.h"
  22
  23#define MAX_NAME_LEN 128
  24
  25static inline u32 str_hash(const char *str)
  26{
  27        return jhash(str, strlen(str), 0);
  28}
  29
  30static inline int elf_hash_bits(void)
  31{
  32        return vmlinux ? ELF_HASH_BITS : 16;
  33}
  34
  35#define elf_hash_add(hashtable, node, key) \
  36        hlist_add_head(node, &hashtable[hash_min(key, elf_hash_bits())])
  37
  38static void elf_hash_init(struct hlist_head *table)
  39{
  40        __hash_init(table, 1U << elf_hash_bits());
  41}
  42
  43#define elf_hash_for_each_possible(name, obj, member, key)                      \
  44        hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member)
  45
  46static void rb_add(struct rb_root *tree, struct rb_node *node,
  47                   int (*cmp)(struct rb_node *, const struct rb_node *))
  48{
  49        struct rb_node **link = &tree->rb_node;
  50        struct rb_node *parent = NULL;
  51
  52        while (*link) {
  53                parent = *link;
  54                if (cmp(node, parent) < 0)
  55                        link = &parent->rb_left;
  56                else
  57                        link = &parent->rb_right;
  58        }
  59
  60        rb_link_node(node, parent, link);
  61        rb_insert_color(node, tree);
  62}
  63
  64static struct rb_node *rb_find_first(const struct rb_root *tree, const void *key,
  65                               int (*cmp)(const void *key, const struct rb_node *))
  66{
  67        struct rb_node *node = tree->rb_node;
  68        struct rb_node *match = NULL;
  69
  70        while (node) {
  71                int c = cmp(key, node);
  72                if (c <= 0) {
  73                        if (!c)
  74                                match = node;
  75                        node = node->rb_left;
  76                } else if (c > 0) {
  77                        node = node->rb_right;
  78                }
  79        }
  80
  81        return match;
  82}
  83
  84static struct rb_node *rb_next_match(struct rb_node *node, const void *key,
  85                                    int (*cmp)(const void *key, const struct rb_node *))
  86{
  87        node = rb_next(node);
  88        if (node && cmp(key, node))
  89                node = NULL;
  90        return node;
  91}
  92
  93#define rb_for_each(tree, node, key, cmp) \
  94        for ((node) = rb_find_first((tree), (key), (cmp)); \
  95             (node); (node) = rb_next_match((node), (key), (cmp)))
  96
  97static int symbol_to_offset(struct rb_node *a, const struct rb_node *b)
  98{
  99        struct symbol *sa = rb_entry(a, struct symbol, node);
 100        struct symbol *sb = rb_entry(b, struct symbol, node);
 101
 102        if (sa->offset < sb->offset)
 103                return -1;
 104        if (sa->offset > sb->offset)
 105                return 1;
 106
 107        if (sa->len < sb->len)
 108                return -1;
 109        if (sa->len > sb->len)
 110                return 1;
 111
 112        sa->alias = sb;
 113
 114        return 0;
 115}
 116
 117static int symbol_by_offset(const void *key, const struct rb_node *node)
 118{
 119        const struct symbol *s = rb_entry(node, struct symbol, node);
 120        const unsigned long *o = key;
 121
 122        if (*o < s->offset)
 123                return -1;
 124        if (*o >= s->offset + s->len)
 125                return 1;
 126
 127        return 0;
 128}
 129
 130struct section *find_section_by_name(const struct elf *elf, const char *name)
 131{
 132        struct section *sec;
 133
 134        elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
 135                if (!strcmp(sec->name, name))
 136                        return sec;
 137
 138        return NULL;
 139}
 140
 141static struct section *find_section_by_index(struct elf *elf,
 142                                             unsigned int idx)
 143{
 144        struct section *sec;
 145
 146        elf_hash_for_each_possible(elf->section_hash, sec, hash, idx)
 147                if (sec->idx == idx)
 148                        return sec;
 149
 150        return NULL;
 151}
 152
 153static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
 154{
 155        struct symbol *sym;
 156
 157        elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
 158                if (sym->idx == idx)
 159                        return sym;
 160
 161        return NULL;
 162}
 163
 164struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)
 165{
 166        struct rb_node *node;
 167
 168        rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
 169                struct symbol *s = rb_entry(node, struct symbol, node);
 170
 171                if (s->offset == offset && s->type != STT_SECTION)
 172                        return s;
 173        }
 174
 175        return NULL;
 176}
 177
 178struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)
 179{
 180        struct rb_node *node;
 181
 182        rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
 183                struct symbol *s = rb_entry(node, struct symbol, node);
 184
 185                if (s->offset == offset && s->type == STT_FUNC)
 186                        return s;
 187        }
 188
 189        return NULL;
 190}
 191
 192struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset)
 193{
 194        struct rb_node *node;
 195
 196        rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
 197                struct symbol *s = rb_entry(node, struct symbol, node);
 198
 199                if (s->type != STT_SECTION)
 200                        return s;
 201        }
 202
 203        return NULL;
 204}
 205
 206struct symbol *find_func_containing(struct section *sec, unsigned long offset)
 207{
 208        struct rb_node *node;
 209
 210        rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
 211                struct symbol *s = rb_entry(node, struct symbol, node);
 212
 213                if (s->type == STT_FUNC)
 214                        return s;
 215        }
 216
 217        return NULL;
 218}
 219
 220struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)
 221{
 222        struct symbol *sym;
 223
 224        elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
 225                if (!strcmp(sym->name, name))
 226                        return sym;
 227
 228        return NULL;
 229}
 230
 231struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
 232                                     unsigned long offset, unsigned int len)
 233{
 234        struct reloc *reloc, *r = NULL;
 235        unsigned long o;
 236
 237        if (!sec->reloc)
 238                return NULL;
 239
 240        sec = sec->reloc;
 241
 242        for_offset_range(o, offset, offset + len) {
 243                elf_hash_for_each_possible(elf->reloc_hash, reloc, hash,
 244                                       sec_offset_hash(sec, o)) {
 245                        if (reloc->sec != sec)
 246                                continue;
 247
 248                        if (reloc->offset >= offset && reloc->offset < offset + len) {
 249                                if (!r || reloc->offset < r->offset)
 250                                        r = reloc;
 251                        }
 252                }
 253                if (r)
 254                        return r;
 255        }
 256
 257        return NULL;
 258}
 259
 260struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset)
 261{
 262        return find_reloc_by_dest_range(elf, sec, offset, 1);
 263}
 264
 265static int read_sections(struct elf *elf)
 266{
 267        Elf_Scn *s = NULL;
 268        struct section *sec;
 269        size_t shstrndx, sections_nr;
 270        int i;
 271
 272        if (elf_getshdrnum(elf->elf, &sections_nr)) {
 273                WARN_ELF("elf_getshdrnum");
 274                return -1;
 275        }
 276
 277        if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
 278                WARN_ELF("elf_getshdrstrndx");
 279                return -1;
 280        }
 281
 282        for (i = 0; i < sections_nr; i++) {
 283                sec = malloc(sizeof(*sec));
 284                if (!sec) {
 285                        perror("malloc");
 286                        return -1;
 287                }
 288                memset(sec, 0, sizeof(*sec));
 289
 290                INIT_LIST_HEAD(&sec->symbol_list);
 291                INIT_LIST_HEAD(&sec->reloc_list);
 292
 293                s = elf_getscn(elf->elf, i);
 294                if (!s) {
 295                        WARN_ELF("elf_getscn");
 296                        return -1;
 297                }
 298
 299                sec->idx = elf_ndxscn(s);
 300
 301                if (!gelf_getshdr(s, &sec->sh)) {
 302                        WARN_ELF("gelf_getshdr");
 303                        return -1;
 304                }
 305
 306                sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
 307                if (!sec->name) {
 308                        WARN_ELF("elf_strptr");
 309                        return -1;
 310                }
 311
 312                if (sec->sh.sh_size != 0) {
 313                        sec->data = elf_getdata(s, NULL);
 314                        if (!sec->data) {
 315                                WARN_ELF("elf_getdata");
 316                                return -1;
 317                        }
 318                        if (sec->data->d_off != 0 ||
 319                            sec->data->d_size != sec->sh.sh_size) {
 320                                WARN("unexpected data attributes for %s",
 321                                     sec->name);
 322                                return -1;
 323                        }
 324                }
 325                sec->len = sec->sh.sh_size;
 326
 327                list_add_tail(&sec->list, &elf->sections);
 328                elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
 329                elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
 330        }
 331
 332        if (stats)
 333                printf("nr_sections: %lu\n", (unsigned long)sections_nr);
 334
 335        /* sanity check, one more call to elf_nextscn() should return NULL */
 336        if (elf_nextscn(elf->elf, s)) {
 337                WARN("section entry mismatch");
 338                return -1;
 339        }
 340
 341        return 0;
 342}
 343
 344static int read_symbols(struct elf *elf)
 345{
 346        struct section *symtab, *symtab_shndx, *sec;
 347        struct symbol *sym, *pfunc;
 348        struct list_head *entry;
 349        struct rb_node *pnode;
 350        int symbols_nr, i;
 351        char *coldstr;
 352        Elf_Data *shndx_data = NULL;
 353        Elf32_Word shndx;
 354
 355        symtab = find_section_by_name(elf, ".symtab");
 356        if (!symtab) {
 357                WARN("missing symbol table");
 358                return -1;
 359        }
 360
 361        symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
 362        if (symtab_shndx)
 363                shndx_data = symtab_shndx->data;
 364
 365        symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
 366
 367        for (i = 0; i < symbols_nr; i++) {
 368                sym = malloc(sizeof(*sym));
 369                if (!sym) {
 370                        perror("malloc");
 371                        return -1;
 372                }
 373                memset(sym, 0, sizeof(*sym));
 374                sym->alias = sym;
 375
 376                sym->idx = i;
 377
 378                if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
 379                                      &shndx)) {
 380                        WARN_ELF("gelf_getsymshndx");
 381                        goto err;
 382                }
 383
 384                sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
 385                                       sym->sym.st_name);
 386                if (!sym->name) {
 387                        WARN_ELF("elf_strptr");
 388                        goto err;
 389                }
 390
 391                sym->type = GELF_ST_TYPE(sym->sym.st_info);
 392                sym->bind = GELF_ST_BIND(sym->sym.st_info);
 393
 394                if ((sym->sym.st_shndx > SHN_UNDEF &&
 395                     sym->sym.st_shndx < SHN_LORESERVE) ||
 396                    (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
 397                        if (sym->sym.st_shndx != SHN_XINDEX)
 398                                shndx = sym->sym.st_shndx;
 399
 400                        sym->sec = find_section_by_index(elf, shndx);
 401                        if (!sym->sec) {
 402                                WARN("couldn't find section for symbol %s",
 403                                     sym->name);
 404                                goto err;
 405                        }
 406                        if (sym->type == STT_SECTION) {
 407                                sym->name = sym->sec->name;
 408                                sym->sec->sym = sym;
 409                        }
 410                } else
 411                        sym->sec = find_section_by_index(elf, 0);
 412
 413                sym->offset = sym->sym.st_value;
 414                sym->len = sym->sym.st_size;
 415
 416                rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset);
 417                pnode = rb_prev(&sym->node);
 418                if (pnode)
 419                        entry = &rb_entry(pnode, struct symbol, node)->list;
 420                else
 421                        entry = &sym->sec->symbol_list;
 422                list_add(&sym->list, entry);
 423                elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
 424                elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
 425        }
 426
 427        if (stats)
 428                printf("nr_symbols: %lu\n", (unsigned long)symbols_nr);
 429
 430        /* Create parent/child links for any cold subfunctions */
 431        list_for_each_entry(sec, &elf->sections, list) {
 432                list_for_each_entry(sym, &sec->symbol_list, list) {
 433                        char pname[MAX_NAME_LEN + 1];
 434                        size_t pnamelen;
 435                        if (sym->type != STT_FUNC)
 436                                continue;
 437
 438                        if (sym->pfunc == NULL)
 439                                sym->pfunc = sym;
 440
 441                        if (sym->cfunc == NULL)
 442                                sym->cfunc = sym;
 443
 444                        coldstr = strstr(sym->name, ".cold");
 445                        if (!coldstr)
 446                                continue;
 447
 448                        pnamelen = coldstr - sym->name;
 449                        if (pnamelen > MAX_NAME_LEN) {
 450                                WARN("%s(): parent function name exceeds maximum length of %d characters",
 451                                     sym->name, MAX_NAME_LEN);
 452                                return -1;
 453                        }
 454
 455                        strncpy(pname, sym->name, pnamelen);
 456                        pname[pnamelen] = '\0';
 457                        pfunc = find_symbol_by_name(elf, pname);
 458
 459                        if (!pfunc) {
 460                                WARN("%s(): can't find parent function",
 461                                     sym->name);
 462                                return -1;
 463                        }
 464
 465                        sym->pfunc = pfunc;
 466                        pfunc->cfunc = sym;
 467
 468                        /*
 469                         * Unfortunately, -fnoreorder-functions puts the child
 470                         * inside the parent.  Remove the overlap so we can
 471                         * have sane assumptions.
 472                         *
 473                         * Note that pfunc->len now no longer matches
 474                         * pfunc->sym.st_size.
 475                         */
 476                        if (sym->sec == pfunc->sec &&
 477                            sym->offset >= pfunc->offset &&
 478                            sym->offset + sym->len == pfunc->offset + pfunc->len) {
 479                                pfunc->len -= sym->len;
 480                        }
 481                }
 482        }
 483
 484        return 0;
 485
 486err:
 487        free(sym);
 488        return -1;
 489}
 490
 491void elf_add_reloc(struct elf *elf, struct reloc *reloc)
 492{
 493        struct section *sec = reloc->sec;
 494
 495        list_add_tail(&reloc->list, &sec->reloc_list);
 496        elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
 497}
 498
 499static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
 500{
 501        if (!gelf_getrel(sec->data, i, &reloc->rel)) {
 502                WARN_ELF("gelf_getrel");
 503                return -1;
 504        }
 505        reloc->type = GELF_R_TYPE(reloc->rel.r_info);
 506        reloc->addend = 0;
 507        reloc->offset = reloc->rel.r_offset;
 508        *symndx = GELF_R_SYM(reloc->rel.r_info);
 509        return 0;
 510}
 511
 512static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
 513{
 514        if (!gelf_getrela(sec->data, i, &reloc->rela)) {
 515                WARN_ELF("gelf_getrela");
 516                return -1;
 517        }
 518        reloc->type = GELF_R_TYPE(reloc->rela.r_info);
 519        reloc->addend = reloc->rela.r_addend;
 520        reloc->offset = reloc->rela.r_offset;
 521        *symndx = GELF_R_SYM(reloc->rela.r_info);
 522        return 0;
 523}
 524
 525static int read_relocs(struct elf *elf)
 526{
 527        struct section *sec;
 528        struct reloc *reloc;
 529        int i;
 530        unsigned int symndx;
 531        unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0;
 532
 533        list_for_each_entry(sec, &elf->sections, list) {
 534                if ((sec->sh.sh_type != SHT_RELA) &&
 535                    (sec->sh.sh_type != SHT_REL))
 536                        continue;
 537
 538                sec->base = find_section_by_index(elf, sec->sh.sh_info);
 539                if (!sec->base) {
 540                        WARN("can't find base section for reloc section %s",
 541                             sec->name);
 542                        return -1;
 543                }
 544
 545                sec->base->reloc = sec;
 546
 547                nr_reloc = 0;
 548                for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
 549                        reloc = malloc(sizeof(*reloc));
 550                        if (!reloc) {
 551                                perror("malloc");
 552                                return -1;
 553                        }
 554                        memset(reloc, 0, sizeof(*reloc));
 555                        switch (sec->sh.sh_type) {
 556                        case SHT_REL:
 557                                if (read_rel_reloc(sec, i, reloc, &symndx))
 558                                        return -1;
 559                                break;
 560                        case SHT_RELA:
 561                                if (read_rela_reloc(sec, i, reloc, &symndx))
 562                                        return -1;
 563                                break;
 564                        default: return -1;
 565                        }
 566
 567                        reloc->sec = sec;
 568                        reloc->idx = i;
 569                        reloc->sym = find_symbol_by_index(elf, symndx);
 570                        if (!reloc->sym) {
 571                                WARN("can't find reloc entry symbol %d for %s",
 572                                     symndx, sec->name);
 573                                return -1;
 574                        }
 575
 576                        elf_add_reloc(elf, reloc);
 577                        nr_reloc++;
 578                }
 579                max_reloc = max(max_reloc, nr_reloc);
 580                tot_reloc += nr_reloc;
 581        }
 582
 583        if (stats) {
 584                printf("max_reloc: %lu\n", max_reloc);
 585                printf("tot_reloc: %lu\n", tot_reloc);
 586        }
 587
 588        return 0;
 589}
 590
 591struct elf *elf_open_read(const char *name, int flags)
 592{
 593        struct elf *elf;
 594        Elf_Cmd cmd;
 595
 596        elf_version(EV_CURRENT);
 597
 598        elf = malloc(sizeof(*elf));
 599        if (!elf) {
 600                perror("malloc");
 601                return NULL;
 602        }
 603        memset(elf, 0, offsetof(struct elf, sections));
 604
 605        INIT_LIST_HEAD(&elf->sections);
 606
 607        elf_hash_init(elf->symbol_hash);
 608        elf_hash_init(elf->symbol_name_hash);
 609        elf_hash_init(elf->section_hash);
 610        elf_hash_init(elf->section_name_hash);
 611        elf_hash_init(elf->reloc_hash);
 612
 613        elf->fd = open(name, flags);
 614        if (elf->fd == -1) {
 615                fprintf(stderr, "objtool: Can't open '%s': %s\n",
 616                        name, strerror(errno));
 617                goto err;
 618        }
 619
 620        if ((flags & O_ACCMODE) == O_RDONLY)
 621                cmd = ELF_C_READ_MMAP;
 622        else if ((flags & O_ACCMODE) == O_RDWR)
 623                cmd = ELF_C_RDWR;
 624        else /* O_WRONLY */
 625                cmd = ELF_C_WRITE;
 626
 627        elf->elf = elf_begin(elf->fd, cmd, NULL);
 628        if (!elf->elf) {
 629                WARN_ELF("elf_begin");
 630                goto err;
 631        }
 632
 633        if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
 634                WARN_ELF("gelf_getehdr");
 635                goto err;
 636        }
 637
 638        if (read_sections(elf))
 639                goto err;
 640
 641        if (read_symbols(elf))
 642                goto err;
 643
 644        if (read_relocs(elf))
 645                goto err;
 646
 647        return elf;
 648
 649err:
 650        elf_close(elf);
 651        return NULL;
 652}
 653
 654struct section *elf_create_section(struct elf *elf, const char *name,
 655                                   unsigned int sh_flags, size_t entsize, int nr)
 656{
 657        struct section *sec, *shstrtab;
 658        size_t size = entsize * nr;
 659        Elf_Scn *s;
 660        Elf_Data *data;
 661
 662        sec = malloc(sizeof(*sec));
 663        if (!sec) {
 664                perror("malloc");
 665                return NULL;
 666        }
 667        memset(sec, 0, sizeof(*sec));
 668
 669        INIT_LIST_HEAD(&sec->symbol_list);
 670        INIT_LIST_HEAD(&sec->reloc_list);
 671
 672        s = elf_newscn(elf->elf);
 673        if (!s) {
 674                WARN_ELF("elf_newscn");
 675                return NULL;
 676        }
 677
 678        sec->name = strdup(name);
 679        if (!sec->name) {
 680                perror("strdup");
 681                return NULL;
 682        }
 683
 684        sec->idx = elf_ndxscn(s);
 685        sec->len = size;
 686        sec->changed = true;
 687
 688        sec->data = elf_newdata(s);
 689        if (!sec->data) {
 690                WARN_ELF("elf_newdata");
 691                return NULL;
 692        }
 693
 694        sec->data->d_size = size;
 695        sec->data->d_align = 1;
 696
 697        if (size) {
 698                sec->data->d_buf = malloc(size);
 699                if (!sec->data->d_buf) {
 700                        perror("malloc");
 701                        return NULL;
 702                }
 703                memset(sec->data->d_buf, 0, size);
 704        }
 705
 706        if (!gelf_getshdr(s, &sec->sh)) {
 707                WARN_ELF("gelf_getshdr");
 708                return NULL;
 709        }
 710
 711        sec->sh.sh_size = size;
 712        sec->sh.sh_entsize = entsize;
 713        sec->sh.sh_type = SHT_PROGBITS;
 714        sec->sh.sh_addralign = 1;
 715        sec->sh.sh_flags = SHF_ALLOC | sh_flags;
 716
 717
 718        /* Add section name to .shstrtab (or .strtab for Clang) */
 719        shstrtab = find_section_by_name(elf, ".shstrtab");
 720        if (!shstrtab)
 721                shstrtab = find_section_by_name(elf, ".strtab");
 722        if (!shstrtab) {
 723                WARN("can't find .shstrtab or .strtab section");
 724                return NULL;
 725        }
 726
 727        s = elf_getscn(elf->elf, shstrtab->idx);
 728        if (!s) {
 729                WARN_ELF("elf_getscn");
 730                return NULL;
 731        }
 732
 733        data = elf_newdata(s);
 734        if (!data) {
 735                WARN_ELF("elf_newdata");
 736                return NULL;
 737        }
 738
 739        data->d_buf = sec->name;
 740        data->d_size = strlen(name) + 1;
 741        data->d_align = 1;
 742
 743        sec->sh.sh_name = shstrtab->len;
 744
 745        shstrtab->len += strlen(name) + 1;
 746        shstrtab->changed = true;
 747
 748        list_add_tail(&sec->list, &elf->sections);
 749        elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
 750        elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
 751
 752        elf->changed = true;
 753
 754        return sec;
 755}
 756
 757static struct section *elf_create_rel_reloc_section(struct elf *elf, struct section *base)
 758{
 759        char *relocname;
 760        struct section *sec;
 761
 762        relocname = malloc(strlen(base->name) + strlen(".rel") + 1);
 763        if (!relocname) {
 764                perror("malloc");
 765                return NULL;
 766        }
 767        strcpy(relocname, ".rel");
 768        strcat(relocname, base->name);
 769
 770        sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0);
 771        free(relocname);
 772        if (!sec)
 773                return NULL;
 774
 775        base->reloc = sec;
 776        sec->base = base;
 777
 778        sec->sh.sh_type = SHT_REL;
 779        sec->sh.sh_addralign = 8;
 780        sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
 781        sec->sh.sh_info = base->idx;
 782        sec->sh.sh_flags = SHF_INFO_LINK;
 783
 784        return sec;
 785}
 786
 787static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base)
 788{
 789        char *relocname;
 790        struct section *sec;
 791
 792        relocname = malloc(strlen(base->name) + strlen(".rela") + 1);
 793        if (!relocname) {
 794                perror("malloc");
 795                return NULL;
 796        }
 797        strcpy(relocname, ".rela");
 798        strcat(relocname, base->name);
 799
 800        sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0);
 801        free(relocname);
 802        if (!sec)
 803                return NULL;
 804
 805        base->reloc = sec;
 806        sec->base = base;
 807
 808        sec->sh.sh_type = SHT_RELA;
 809        sec->sh.sh_addralign = 8;
 810        sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
 811        sec->sh.sh_info = base->idx;
 812        sec->sh.sh_flags = SHF_INFO_LINK;
 813
 814        return sec;
 815}
 816
 817struct section *elf_create_reloc_section(struct elf *elf,
 818                                         struct section *base,
 819                                         int reltype)
 820{
 821        switch (reltype) {
 822        case SHT_REL:  return elf_create_rel_reloc_section(elf, base);
 823        case SHT_RELA: return elf_create_rela_reloc_section(elf, base);
 824        default:       return NULL;
 825        }
 826}
 827
 828static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
 829{
 830        struct reloc *reloc;
 831        int idx = 0, size;
 832        GElf_Rel *relocs;
 833
 834        /* Allocate a buffer for relocations */
 835        size = nr * sizeof(*relocs);
 836        relocs = malloc(size);
 837        if (!relocs) {
 838                perror("malloc");
 839                return -1;
 840        }
 841
 842        sec->data->d_buf = relocs;
 843        sec->data->d_size = size;
 844
 845        sec->sh.sh_size = size;
 846
 847        idx = 0;
 848        list_for_each_entry(reloc, &sec->reloc_list, list) {
 849                relocs[idx].r_offset = reloc->offset;
 850                relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
 851                idx++;
 852        }
 853
 854        return 0;
 855}
 856
 857static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
 858{
 859        struct reloc *reloc;
 860        int idx = 0, size;
 861        GElf_Rela *relocs;
 862
 863        /* Allocate a buffer for relocations with addends */
 864        size = nr * sizeof(*relocs);
 865        relocs = malloc(size);
 866        if (!relocs) {
 867                perror("malloc");
 868                return -1;
 869        }
 870
 871        sec->data->d_buf = relocs;
 872        sec->data->d_size = size;
 873
 874        sec->sh.sh_size = size;
 875
 876        idx = 0;
 877        list_for_each_entry(reloc, &sec->reloc_list, list) {
 878                relocs[idx].r_offset = reloc->offset;
 879                relocs[idx].r_addend = reloc->addend;
 880                relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
 881                idx++;
 882        }
 883
 884        return 0;
 885}
 886
 887int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
 888{
 889        struct reloc *reloc;
 890        int nr;
 891
 892        sec->changed = true;
 893        elf->changed = true;
 894
 895        nr = 0;
 896        list_for_each_entry(reloc, &sec->reloc_list, list)
 897                nr++;
 898
 899        switch (sec->sh.sh_type) {
 900        case SHT_REL:  return elf_rebuild_rel_reloc_section(sec, nr);
 901        case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr);
 902        default:       return -1;
 903        }
 904}
 905
 906int elf_write_insn(struct elf *elf, struct section *sec,
 907                   unsigned long offset, unsigned int len,
 908                   const char *insn)
 909{
 910        Elf_Data *data = sec->data;
 911
 912        if (data->d_type != ELF_T_BYTE || data->d_off) {
 913                WARN("write to unexpected data for section: %s", sec->name);
 914                return -1;
 915        }
 916
 917        memcpy(data->d_buf + offset, insn, len);
 918        elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY);
 919
 920        elf->changed = true;
 921
 922        return 0;
 923}
 924
 925int elf_write_reloc(struct elf *elf, struct reloc *reloc)
 926{
 927        struct section *sec = reloc->sec;
 928
 929        if (sec->sh.sh_type == SHT_REL) {
 930                reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
 931                reloc->rel.r_offset = reloc->offset;
 932
 933                if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) {
 934                        WARN_ELF("gelf_update_rel");
 935                        return -1;
 936                }
 937        } else {
 938                reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
 939                reloc->rela.r_addend = reloc->addend;
 940                reloc->rela.r_offset = reloc->offset;
 941
 942                if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) {
 943                        WARN_ELF("gelf_update_rela");
 944                        return -1;
 945                }
 946        }
 947
 948        elf->changed = true;
 949
 950        return 0;
 951}
 952
 953int elf_write(struct elf *elf)
 954{
 955        struct section *sec;
 956        Elf_Scn *s;
 957
 958        /* Update section headers for changed sections: */
 959        list_for_each_entry(sec, &elf->sections, list) {
 960                if (sec->changed) {
 961                        s = elf_getscn(elf->elf, sec->idx);
 962                        if (!s) {
 963                                WARN_ELF("elf_getscn");
 964                                return -1;
 965                        }
 966                        if (!gelf_update_shdr(s, &sec->sh)) {
 967                                WARN_ELF("gelf_update_shdr");
 968                                return -1;
 969                        }
 970
 971                        sec->changed = false;
 972                }
 973        }
 974
 975        /* Make sure the new section header entries get updated properly. */
 976        elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY);
 977
 978        /* Write all changes to the file. */
 979        if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
 980                WARN_ELF("elf_update");
 981                return -1;
 982        }
 983
 984        elf->changed = false;
 985
 986        return 0;
 987}
 988
 989void elf_close(struct elf *elf)
 990{
 991        struct section *sec, *tmpsec;
 992        struct symbol *sym, *tmpsym;
 993        struct reloc *reloc, *tmpreloc;
 994
 995        if (elf->elf)
 996                elf_end(elf->elf);
 997
 998        if (elf->fd > 0)
 999                close(elf->fd);
1000
1001        list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
1002                list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
1003                        list_del(&sym->list);
1004                        hash_del(&sym->hash);
1005                        free(sym);
1006                }
1007                list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
1008                        list_del(&reloc->list);
1009                        hash_del(&reloc->hash);
1010                        free(reloc);
1011                }
1012                list_del(&sec->list);
1013                free(sec);
1014        }
1015
1016        free(elf);
1017}
1018