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