elf.c 21.6 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * elf.c - ELF access library
 *
 * Adapted from kpatch (https://github.com/dynup/kpatch):
 * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com>
 * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
17
#include <errno.h>
18
#include <objtool/builtin.h>
19

20 21
#include <objtool/elf.h>
#include <objtool/warn.h>
22

23 24
#define MAX_NAME_LEN 128

25 26 27 28 29
static inline u32 str_hash(const char *str)
{
	return jhash(str, strlen(str), 0);
}

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
static inline int elf_hash_bits(void)
{
	return vmlinux ? ELF_HASH_BITS : 16;
}

#define elf_hash_add(hashtable, node, key) \
	hlist_add_head(node, &hashtable[hash_min(key, elf_hash_bits())])

static void elf_hash_init(struct hlist_head *table)
{
	__hash_init(table, 1U << elf_hash_bits());
}

#define elf_hash_for_each_possible(name, obj, member, key)			\
	hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member)

46
static bool symbol_to_offset(struct rb_node *a, const struct rb_node *b)
47 48 49 50 51
{
	struct symbol *sa = rb_entry(a, struct symbol, node);
	struct symbol *sb = rb_entry(b, struct symbol, node);

	if (sa->offset < sb->offset)
52
		return true;
53
	if (sa->offset > sb->offset)
54
		return false;
55 56

	if (sa->len < sb->len)
57
		return true;
58
	if (sa->len > sb->len)
59
		return false;
60 61 62

	sa->alias = sb;

63
	return false;
64 65 66 67 68 69 70 71 72
}

static int symbol_by_offset(const void *key, const struct rb_node *node)
{
	const struct symbol *s = rb_entry(node, struct symbol, node);
	const unsigned long *o = key;

	if (*o < s->offset)
		return -1;
73
	if (*o >= s->offset + s->len)
74 75 76 77 78
		return 1;

	return 0;
}

79
struct section *find_section_by_name(const struct elf *elf, const char *name)
80 81 82
{
	struct section *sec;

83
	elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
84 85 86 87 88 89 90 91 92 93 94
		if (!strcmp(sec->name, name))
			return sec;

	return NULL;
}

static struct section *find_section_by_index(struct elf *elf,
					     unsigned int idx)
{
	struct section *sec;

95
	elf_hash_for_each_possible(elf->section_hash, sec, hash, idx)
96 97 98 99 100 101 102 103 104 105
		if (sec->idx == idx)
			return sec;

	return NULL;
}

static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
{
	struct symbol *sym;

106
	elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
107 108
		if (sym->idx == idx)
			return sym;
109 110 111 112 113 114

	return NULL;
}

struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)
{
115
	struct rb_node *node;
116

117
	rb_for_each(node, &offset, &sec->symbol_tree, symbol_by_offset) {
118 119 120 121 122
		struct symbol *s = rb_entry(node, struct symbol, node);

		if (s->offset == offset && s->type != STT_SECTION)
			return s;
	}
123 124 125 126 127 128

	return NULL;
}

struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)
{
129
	struct rb_node *node;
130

131
	rb_for_each(node, &offset, &sec->symbol_tree, symbol_by_offset) {
132 133 134 135 136
		struct symbol *s = rb_entry(node, struct symbol, node);

		if (s->offset == offset && s->type == STT_FUNC)
			return s;
	}
137 138 139 140

	return NULL;
}

141
struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset)
142
{
143
	struct rb_node *node;
144

145
	rb_for_each(node, &offset, &sec->symbol_tree, symbol_by_offset) {
146 147 148 149 150
		struct symbol *s = rb_entry(node, struct symbol, node);

		if (s->type != STT_SECTION)
			return s;
	}
151 152 153 154

	return NULL;
}

155
struct symbol *find_func_containing(struct section *sec, unsigned long offset)
156 157 158
{
	struct rb_node *node;

159
	rb_for_each(node, &offset, &sec->symbol_tree, symbol_by_offset) {
160 161 162 163 164 165 166 167 168
		struct symbol *s = rb_entry(node, struct symbol, node);

		if (s->type == STT_FUNC)
			return s;
	}

	return NULL;
}

169
struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)
170 171 172
{
	struct symbol *sym;

173
	elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
174 175
		if (!strcmp(sym->name, name))
			return sym;
176 177 178 179

	return NULL;
}

M
Matt Helsley 已提交
180
struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
181
				     unsigned long offset, unsigned int len)
182
{
M
Matt Helsley 已提交
183
	struct reloc *reloc, *r = NULL;
184
	unsigned long o;
185

M
Matt Helsley 已提交
186
	if (!sec->reloc)
187 188
		return NULL;

M
Matt Helsley 已提交
189
	sec = sec->reloc;
190

191
	for_offset_range(o, offset, offset + len) {
M
Matt Helsley 已提交
192
		elf_hash_for_each_possible(elf->reloc_hash, reloc, hash,
193
				       sec_offset_hash(sec, o)) {
M
Matt Helsley 已提交
194
			if (reloc->sec != sec)
195 196
				continue;

M
Matt Helsley 已提交
197 198 199
			if (reloc->offset >= offset && reloc->offset < offset + len) {
				if (!r || reloc->offset < r->offset)
					r = reloc;
200
			}
201
		}
202 203
		if (r)
			return r;
204
	}
205 206 207 208

	return NULL;
}

M
Matt Helsley 已提交
209
struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset)
210
{
M
Matt Helsley 已提交
211
	return find_reloc_by_dest_range(elf, sec, offset, 1);
212 213
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
void insn_to_reloc_sym_addend(struct section *sec, unsigned long offset,
			      struct reloc *reloc)
{
	if (sec->sym) {
		reloc->sym = sec->sym;
		reloc->addend = offset;
		return;
	}

	/*
	 * The Clang assembler strips section symbols, so we have to reference
	 * the function symbol instead:
	 */
	reloc->sym = find_symbol_containing(sec, offset);
	if (!reloc->sym) {
		/*
		 * Hack alert.  This happens when we need to reference the NOP
		 * pad insn immediately after the function.
		 */
		reloc->sym = find_symbol_containing(sec, offset - 1);
	}

	if (reloc->sym)
		reloc->addend = offset - reloc->sym->offset;
}

240 241 242 243 244 245 246 247
static int read_sections(struct elf *elf)
{
	Elf_Scn *s = NULL;
	struct section *sec;
	size_t shstrndx, sections_nr;
	int i;

	if (elf_getshdrnum(elf->elf, &sections_nr)) {
248
		WARN_ELF("elf_getshdrnum");
249 250 251 252
		return -1;
	}

	if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
253
		WARN_ELF("elf_getshdrstrndx");
254 255 256 257 258 259 260 261 262 263 264
		return -1;
	}

	for (i = 0; i < sections_nr; i++) {
		sec = malloc(sizeof(*sec));
		if (!sec) {
			perror("malloc");
			return -1;
		}
		memset(sec, 0, sizeof(*sec));

265
		INIT_LIST_HEAD(&sec->symbol_list);
M
Matt Helsley 已提交
266
		INIT_LIST_HEAD(&sec->reloc_list);
267 268 269

		s = elf_getscn(elf->elf, i);
		if (!s) {
270
			WARN_ELF("elf_getscn");
271 272 273 274 275 276
			return -1;
		}

		sec->idx = elf_ndxscn(s);

		if (!gelf_getshdr(s, &sec->sh)) {
277
			WARN_ELF("gelf_getshdr");
278 279 280 281 282
			return -1;
		}

		sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
		if (!sec->name) {
283
			WARN_ELF("elf_strptr");
284 285 286
			return -1;
		}

287 288 289 290 291 292 293 294 295 296 297 298
		if (sec->sh.sh_size != 0) {
			sec->data = elf_getdata(s, NULL);
			if (!sec->data) {
				WARN_ELF("elf_getdata");
				return -1;
			}
			if (sec->data->d_off != 0 ||
			    sec->data->d_size != sec->sh.sh_size) {
				WARN("unexpected data attributes for %s",
				     sec->name);
				return -1;
			}
299
		}
300
		sec->len = sec->sh.sh_size;
301 302

		list_add_tail(&sec->list, &elf->sections);
303 304
		elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
		elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
305 306
	}

P
Peter Zijlstra 已提交
307 308 309
	if (stats)
		printf("nr_sections: %lu\n", (unsigned long)sections_nr);

310 311 312 313 314 315 316 317 318 319 320
	/* sanity check, one more call to elf_nextscn() should return NULL */
	if (elf_nextscn(elf->elf, s)) {
		WARN("section entry mismatch");
		return -1;
	}

	return 0;
}

static int read_symbols(struct elf *elf)
{
321
	struct section *symtab, *symtab_shndx, *sec;
322 323 324
	struct symbol *sym, *pfunc;
	struct list_head *entry;
	struct rb_node *pnode;
325
	int symbols_nr, i;
326
	char *coldstr;
327 328
	Elf_Data *shndx_data = NULL;
	Elf32_Word shndx;
329 330 331

	symtab = find_section_by_name(elf, ".symtab");
	if (!symtab) {
332 333 334 335 336
		/*
		 * A missing symbol table is actually possible if it's an empty
		 * .o file.  This can happen for thunk_64.o.
		 */
		return 0;
337 338
	}

339 340 341 342
	symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
	if (symtab_shndx)
		shndx_data = symtab_shndx->data;

343 344 345 346 347 348 349 350 351
	symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;

	for (i = 0; i < symbols_nr; i++) {
		sym = malloc(sizeof(*sym));
		if (!sym) {
			perror("malloc");
			return -1;
		}
		memset(sym, 0, sizeof(*sym));
352
		sym->alias = sym;
353 354 355

		sym->idx = i;

356 357 358
		if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
				      &shndx)) {
			WARN_ELF("gelf_getsymshndx");
359 360 361 362 363 364
			goto err;
		}

		sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
				       sym->sym.st_name);
		if (!sym->name) {
365
			WARN_ELF("elf_strptr");
366 367 368 369 370 371
			goto err;
		}

		sym->type = GELF_ST_TYPE(sym->sym.st_info);
		sym->bind = GELF_ST_BIND(sym->sym.st_info);

372 373 374 375 376 377 378
		if ((sym->sym.st_shndx > SHN_UNDEF &&
		     sym->sym.st_shndx < SHN_LORESERVE) ||
		    (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
			if (sym->sym.st_shndx != SHN_XINDEX)
				shndx = sym->sym.st_shndx;

			sym->sec = find_section_by_index(elf, shndx);
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
			if (!sym->sec) {
				WARN("couldn't find section for symbol %s",
				     sym->name);
				goto err;
			}
			if (sym->type == STT_SECTION) {
				sym->name = sym->sec->name;
				sym->sec->sym = sym;
			}
		} else
			sym->sec = find_section_by_index(elf, 0);

		sym->offset = sym->sym.st_value;
		sym->len = sym->sym.st_size;

394
		rb_add(&sym->node, &sym->sec->symbol_tree, symbol_to_offset);
395 396 397 398 399
		pnode = rb_prev(&sym->node);
		if (pnode)
			entry = &rb_entry(pnode, struct symbol, node)->list;
		else
			entry = &sym->sec->symbol_list;
400
		list_add(&sym->list, entry);
401 402
		elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
		elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
403 404 405 406 407 408 409

		/*
		 * Don't store empty STT_NOTYPE symbols in the rbtree.  They
		 * can exist within a function, confusing the sorting.
		 */
		if (!sym->len)
			rb_erase(&sym->node, &sym->sec->symbol_tree);
410 411
	}

P
Peter Zijlstra 已提交
412 413 414
	if (stats)
		printf("nr_symbols: %lu\n", (unsigned long)symbols_nr);

415 416 417
	/* Create parent/child links for any cold subfunctions */
	list_for_each_entry(sec, &elf->sections, list) {
		list_for_each_entry(sym, &sec->symbol_list, list) {
418 419
			char pname[MAX_NAME_LEN + 1];
			size_t pnamelen;
420 421
			if (sym->type != STT_FUNC)
				continue;
422 423 424 425 426 427 428

			if (sym->pfunc == NULL)
				sym->pfunc = sym;

			if (sym->cfunc == NULL)
				sym->cfunc = sym;

429
			coldstr = strstr(sym->name, ".cold");
430 431 432
			if (!coldstr)
				continue;

433 434 435 436 437 438 439 440 441 442
			pnamelen = coldstr - sym->name;
			if (pnamelen > MAX_NAME_LEN) {
				WARN("%s(): parent function name exceeds maximum length of %d characters",
				     sym->name, MAX_NAME_LEN);
				return -1;
			}

			strncpy(pname, sym->name, pnamelen);
			pname[pnamelen] = '\0';
			pfunc = find_symbol_by_name(elf, pname);
443 444 445 446

			if (!pfunc) {
				WARN("%s(): can't find parent function",
				     sym->name);
447
				return -1;
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
			}

			sym->pfunc = pfunc;
			pfunc->cfunc = sym;

			/*
			 * Unfortunately, -fnoreorder-functions puts the child
			 * inside the parent.  Remove the overlap so we can
			 * have sane assumptions.
			 *
			 * Note that pfunc->len now no longer matches
			 * pfunc->sym.st_size.
			 */
			if (sym->sec == pfunc->sec &&
			    sym->offset >= pfunc->offset &&
			    sym->offset + sym->len == pfunc->offset + pfunc->len) {
				pfunc->len -= sym->len;
465 466 467 468
			}
		}
	}

469 470 471 472 473 474 475
	return 0;

err:
	free(sym);
	return -1;
}

M
Matt Helsley 已提交
476
void elf_add_reloc(struct elf *elf, struct reloc *reloc)
477
{
M
Matt Helsley 已提交
478
	struct section *sec = reloc->sec;
479

M
Matt Helsley 已提交
480 481
	list_add_tail(&reloc->list, &sec->reloc_list);
	elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
482 483

	sec->changed = true;
484 485
}

486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
{
	if (!gelf_getrel(sec->data, i, &reloc->rel)) {
		WARN_ELF("gelf_getrel");
		return -1;
	}
	reloc->type = GELF_R_TYPE(reloc->rel.r_info);
	reloc->addend = 0;
	reloc->offset = reloc->rel.r_offset;
	*symndx = GELF_R_SYM(reloc->rel.r_info);
	return 0;
}

static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
{
	if (!gelf_getrela(sec->data, i, &reloc->rela)) {
		WARN_ELF("gelf_getrela");
		return -1;
	}
	reloc->type = GELF_R_TYPE(reloc->rela.r_info);
	reloc->addend = reloc->rela.r_addend;
	reloc->offset = reloc->rela.r_offset;
	*symndx = GELF_R_SYM(reloc->rela.r_info);
	return 0;
}

M
Matt Helsley 已提交
512
static int read_relocs(struct elf *elf)
513 514
{
	struct section *sec;
M
Matt Helsley 已提交
515
	struct reloc *reloc;
516 517
	int i;
	unsigned int symndx;
M
Matt Helsley 已提交
518
	unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0;
519 520

	list_for_each_entry(sec, &elf->sections, list) {
521 522
		if ((sec->sh.sh_type != SHT_RELA) &&
		    (sec->sh.sh_type != SHT_REL))
523 524
			continue;

525
		sec->base = find_section_by_index(elf, sec->sh.sh_info);
526
		if (!sec->base) {
M
Matt Helsley 已提交
527
			WARN("can't find base section for reloc section %s",
528 529 530 531
			     sec->name);
			return -1;
		}

M
Matt Helsley 已提交
532
		sec->base->reloc = sec;
533

M
Matt Helsley 已提交
534
		nr_reloc = 0;
535
		for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
M
Matt Helsley 已提交
536 537
			reloc = malloc(sizeof(*reloc));
			if (!reloc) {
538 539 540
				perror("malloc");
				return -1;
			}
M
Matt Helsley 已提交
541
			memset(reloc, 0, sizeof(*reloc));
542 543 544 545 546 547 548 549 550 551
			switch (sec->sh.sh_type) {
			case SHT_REL:
				if (read_rel_reloc(sec, i, reloc, &symndx))
					return -1;
				break;
			case SHT_RELA:
				if (read_rela_reloc(sec, i, reloc, &symndx))
					return -1;
				break;
			default: return -1;
552 553
			}

M
Matt Helsley 已提交
554
			reloc->sec = sec;
555 556
			reloc->idx = i;
			reloc->sym = find_symbol_by_index(elf, symndx);
M
Matt Helsley 已提交
557 558
			if (!reloc->sym) {
				WARN("can't find reloc entry symbol %d for %s",
559 560 561
				     symndx, sec->name);
				return -1;
			}
562

563 564 565
			list_add_tail(&reloc->list, &sec->reloc_list);
			elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));

M
Matt Helsley 已提交
566
			nr_reloc++;
567
		}
M
Matt Helsley 已提交
568 569
		max_reloc = max(max_reloc, nr_reloc);
		tot_reloc += nr_reloc;
P
Peter Zijlstra 已提交
570 571 572
	}

	if (stats) {
M
Matt Helsley 已提交
573 574
		printf("max_reloc: %lu\n", max_reloc);
		printf("tot_reloc: %lu\n", tot_reloc);
575 576 577 578 579
	}

	return 0;
}

580
struct elf *elf_open_read(const char *name, int flags)
581 582
{
	struct elf *elf;
583
	Elf_Cmd cmd;
584 585 586 587 588 589 590 591

	elf_version(EV_CURRENT);

	elf = malloc(sizeof(*elf));
	if (!elf) {
		perror("malloc");
		return NULL;
	}
592
	memset(elf, 0, offsetof(struct elf, sections));
593 594 595

	INIT_LIST_HEAD(&elf->sections);

596 597 598 599
	elf_hash_init(elf->symbol_hash);
	elf_hash_init(elf->symbol_name_hash);
	elf_hash_init(elf->section_hash);
	elf_hash_init(elf->section_name_hash);
M
Matt Helsley 已提交
600
	elf_hash_init(elf->reloc_hash);
601

602
	elf->fd = open(name, flags);
603
	if (elf->fd == -1) {
604 605
		fprintf(stderr, "objtool: Can't open '%s': %s\n",
			name, strerror(errno));
606 607 608
		goto err;
	}

609 610 611 612 613 614 615 616
	if ((flags & O_ACCMODE) == O_RDONLY)
		cmd = ELF_C_READ_MMAP;
	else if ((flags & O_ACCMODE) == O_RDWR)
		cmd = ELF_C_RDWR;
	else /* O_WRONLY */
		cmd = ELF_C_WRITE;

	elf->elf = elf_begin(elf->fd, cmd, NULL);
617
	if (!elf->elf) {
618
		WARN_ELF("elf_begin");
619 620 621 622
		goto err;
	}

	if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
623
		WARN_ELF("gelf_getehdr");
624 625 626 627 628 629 630 631 632
		goto err;
	}

	if (read_sections(elf))
		goto err;

	if (read_symbols(elf))
		goto err;

M
Matt Helsley 已提交
633
	if (read_relocs(elf))
634 635 636 637 638 639 640 641 642
		goto err;

	return elf;

err:
	elf_close(elf);
	return NULL;
}

643
struct section *elf_create_section(struct elf *elf, const char *name,
644
				   unsigned int sh_flags, size_t entsize, int nr)
645 646 647
{
	struct section *sec, *shstrtab;
	size_t size = entsize * nr;
648
	Elf_Scn *s;
649 650 651 652 653 654 655 656 657 658
	Elf_Data *data;

	sec = malloc(sizeof(*sec));
	if (!sec) {
		perror("malloc");
		return NULL;
	}
	memset(sec, 0, sizeof(*sec));

	INIT_LIST_HEAD(&sec->symbol_list);
M
Matt Helsley 已提交
659
	INIT_LIST_HEAD(&sec->reloc_list);
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703

	s = elf_newscn(elf->elf);
	if (!s) {
		WARN_ELF("elf_newscn");
		return NULL;
	}

	sec->name = strdup(name);
	if (!sec->name) {
		perror("strdup");
		return NULL;
	}

	sec->idx = elf_ndxscn(s);
	sec->len = size;
	sec->changed = true;

	sec->data = elf_newdata(s);
	if (!sec->data) {
		WARN_ELF("elf_newdata");
		return NULL;
	}

	sec->data->d_size = size;
	sec->data->d_align = 1;

	if (size) {
		sec->data->d_buf = malloc(size);
		if (!sec->data->d_buf) {
			perror("malloc");
			return NULL;
		}
		memset(sec->data->d_buf, 0, size);
	}

	if (!gelf_getshdr(s, &sec->sh)) {
		WARN_ELF("gelf_getshdr");
		return NULL;
	}

	sec->sh.sh_size = size;
	sec->sh.sh_entsize = entsize;
	sec->sh.sh_type = SHT_PROGBITS;
	sec->sh.sh_addralign = 1;
704
	sec->sh.sh_flags = SHF_ALLOC | sh_flags;
705 706


707
	/* Add section name to .shstrtab (or .strtab for Clang) */
708
	shstrtab = find_section_by_name(elf, ".shstrtab");
709 710
	if (!shstrtab)
		shstrtab = find_section_by_name(elf, ".strtab");
711
	if (!shstrtab) {
712
		WARN("can't find .shstrtab or .strtab section");
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
		return NULL;
	}

	s = elf_getscn(elf->elf, shstrtab->idx);
	if (!s) {
		WARN_ELF("elf_getscn");
		return NULL;
	}

	data = elf_newdata(s);
	if (!data) {
		WARN_ELF("elf_newdata");
		return NULL;
	}

	data->d_buf = sec->name;
	data->d_size = strlen(name) + 1;
	data->d_align = 1;

	sec->sh.sh_name = shstrtab->len;

	shstrtab->len += strlen(name) + 1;
	shstrtab->changed = true;

737
	list_add_tail(&sec->list, &elf->sections);
738 739
	elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
	elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
740

741 742
	elf->changed = true;

743 744 745
	return sec;
}

746 747 748 749 750 751 752 753 754 755 756 757 758
static struct section *elf_create_rel_reloc_section(struct elf *elf, struct section *base)
{
	char *relocname;
	struct section *sec;

	relocname = malloc(strlen(base->name) + strlen(".rel") + 1);
	if (!relocname) {
		perror("malloc");
		return NULL;
	}
	strcpy(relocname, ".rel");
	strcat(relocname, base->name);

759
	sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0);
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
	free(relocname);
	if (!sec)
		return NULL;

	base->reloc = sec;
	sec->base = base;

	sec->sh.sh_type = SHT_REL;
	sec->sh.sh_addralign = 8;
	sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
	sec->sh.sh_info = base->idx;
	sec->sh.sh_flags = SHF_INFO_LINK;

	return sec;
}

static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base)
777
{
M
Matt Helsley 已提交
778
	char *relocname;
779 780
	struct section *sec;

M
Matt Helsley 已提交
781 782
	relocname = malloc(strlen(base->name) + strlen(".rela") + 1);
	if (!relocname) {
783 784 785
		perror("malloc");
		return NULL;
	}
M
Matt Helsley 已提交
786 787
	strcpy(relocname, ".rela");
	strcat(relocname, base->name);
788

789
	sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0);
M
Matt Helsley 已提交
790
	free(relocname);
791 792 793
	if (!sec)
		return NULL;

M
Matt Helsley 已提交
794
	base->reloc = sec;
795 796 797 798 799 800 801 802 803 804 805
	sec->base = base;

	sec->sh.sh_type = SHT_RELA;
	sec->sh.sh_addralign = 8;
	sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
	sec->sh.sh_info = base->idx;
	sec->sh.sh_flags = SHF_INFO_LINK;

	return sec;
}

806 807 808 809 810 811 812 813 814 815 816 817
struct section *elf_create_reloc_section(struct elf *elf,
					 struct section *base,
					 int reltype)
{
	switch (reltype) {
	case SHT_REL:  return elf_create_rel_reloc_section(elf, base);
	case SHT_RELA: return elf_create_rela_reloc_section(elf, base);
	default:       return NULL;
	}
}

static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
818
{
M
Matt Helsley 已提交
819
	struct reloc *reloc;
820
	int idx = 0, size;
821
	void *buf;
822

823
	/* Allocate a buffer for relocations */
824 825 826
	size = nr * sizeof(GElf_Rel);
	buf = malloc(size);
	if (!buf) {
827 828 829 830
		perror("malloc");
		return -1;
	}

831
	sec->data->d_buf = buf;
832
	sec->data->d_size = size;
833
	sec->data->d_type = ELF_T_REL;
834 835 836 837 838

	sec->sh.sh_size = size;

	idx = 0;
	list_for_each_entry(reloc, &sec->reloc_list, list) {
839 840 841
		reloc->rel.r_offset = reloc->offset;
		reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
		gelf_update_rel(sec->data, idx, &reloc->rel);
842 843 844 845 846
		idx++;
	}

	return 0;
}
847

848 849 850 851
static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
{
	struct reloc *reloc;
	int idx = 0, size;
852
	void *buf;
853 854

	/* Allocate a buffer for relocations with addends */
855 856 857
	size = nr * sizeof(GElf_Rela);
	buf = malloc(size);
	if (!buf) {
858 859 860 861
		perror("malloc");
		return -1;
	}

862
	sec->data->d_buf = buf;
863
	sec->data->d_size = size;
864
	sec->data->d_type = ELF_T_RELA;
865 866 867 868

	sec->sh.sh_size = size;

	idx = 0;
M
Matt Helsley 已提交
869
	list_for_each_entry(reloc, &sec->reloc_list, list) {
870 871 872 873
		reloc->rela.r_offset = reloc->offset;
		reloc->rela.r_addend = reloc->addend;
		reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
		gelf_update_rela(sec->data, idx, &reloc->rela);
874 875 876 877 878 879
		idx++;
	}

	return 0;
}

880
static int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
{
	struct reloc *reloc;
	int nr;

	nr = 0;
	list_for_each_entry(reloc, &sec->reloc_list, list)
		nr++;

	switch (sec->sh.sh_type) {
	case SHT_REL:  return elf_rebuild_rel_reloc_section(sec, nr);
	case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr);
	default:       return -1;
	}
}

896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
int elf_write_insn(struct elf *elf, struct section *sec,
		   unsigned long offset, unsigned int len,
		   const char *insn)
{
	Elf_Data *data = sec->data;

	if (data->d_type != ELF_T_BYTE || data->d_off) {
		WARN("write to unexpected data for section: %s", sec->name);
		return -1;
	}

	memcpy(data->d_buf + offset, insn, len);
	elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY);

	elf->changed = true;

	return 0;
}

915
int elf_write_reloc(struct elf *elf, struct reloc *reloc)
916
{
917
	struct section *sec = reloc->sec;
918

919 920 921
	if (sec->sh.sh_type == SHT_REL) {
		reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
		reloc->rel.r_offset = reloc->offset;
922

923 924 925 926 927 928 929 930 931 932 933 934 935
		if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) {
			WARN_ELF("gelf_update_rel");
			return -1;
		}
	} else {
		reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
		reloc->rela.r_addend = reloc->addend;
		reloc->rela.r_offset = reloc->offset;

		if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) {
			WARN_ELF("gelf_update_rela");
			return -1;
		}
936 937 938 939 940 941 942
	}

	elf->changed = true;

	return 0;
}

943
int elf_write(struct elf *elf)
944 945 946 947
{
	struct section *sec;
	Elf_Scn *s;

948
	/* Update changed relocation sections and section headers: */
949 950
	list_for_each_entry(sec, &elf->sections, list) {
		if (sec->changed) {
951 952 953 954 955 956
			if (sec->base &&
			    elf_rebuild_reloc_section(elf, sec)) {
				WARN("elf_rebuild_reloc_section");
				return -1;
			}

957 958 959 960 961
			s = elf_getscn(elf->elf, sec->idx);
			if (!s) {
				WARN_ELF("elf_getscn");
				return -1;
			}
962
			if (!gelf_update_shdr(s, &sec->sh)) {
963 964 965
				WARN_ELF("gelf_update_shdr");
				return -1;
			}
966 967

			sec->changed = false;
968
			elf->changed = true;
969 970 971
		}
	}

972 973 974 975
	/* Make sure the new section header entries get updated properly. */
	elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY);

	/* Write all changes to the file. */
976 977 978 979 980
	if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
		WARN_ELF("elf_update");
		return -1;
	}

981 982
	elf->changed = false;

983 984 985
	return 0;
}

986 987 988 989
void elf_close(struct elf *elf)
{
	struct section *sec, *tmpsec;
	struct symbol *sym, *tmpsym;
M
Matt Helsley 已提交
990
	struct reloc *reloc, *tmpreloc;
991

992 993 994 995 996 997
	if (elf->elf)
		elf_end(elf->elf);

	if (elf->fd > 0)
		close(elf->fd);

998
	list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
999
		list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
1000
			list_del(&sym->list);
1001
			hash_del(&sym->hash);
1002 1003
			free(sym);
		}
M
Matt Helsley 已提交
1004 1005 1006 1007
		list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
			list_del(&reloc->list);
			hash_del(&reloc->hash);
			free(reloc);
1008 1009 1010 1011
		}
		list_del(&sec->list);
		free(sec);
	}
1012

1013 1014
	free(elf);
}