elf.c 21.4 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
}

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
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 已提交
510
static int read_relocs(struct elf *elf)
511 512
{
	struct section *sec;
M
Matt Helsley 已提交
513
	struct reloc *reloc;
514 515
	int i;
	unsigned int symndx;
M
Matt Helsley 已提交
516
	unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0;
517 518

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

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

M
Matt Helsley 已提交
530
		sec->base->reloc = sec;
531

M
Matt Helsley 已提交
532
		nr_reloc = 0;
533
		for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
M
Matt Helsley 已提交
534 535
			reloc = malloc(sizeof(*reloc));
			if (!reloc) {
536 537 538
				perror("malloc");
				return -1;
			}
M
Matt Helsley 已提交
539
			memset(reloc, 0, sizeof(*reloc));
540 541 542 543 544 545 546 547 548 549
			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;
550 551
			}

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

M
Matt Helsley 已提交
561 562
			elf_add_reloc(elf, reloc);
			nr_reloc++;
563
		}
M
Matt Helsley 已提交
564 565
		max_reloc = max(max_reloc, nr_reloc);
		tot_reloc += nr_reloc;
P
Peter Zijlstra 已提交
566 567 568
	}

	if (stats) {
M
Matt Helsley 已提交
569 570
		printf("max_reloc: %lu\n", max_reloc);
		printf("tot_reloc: %lu\n", tot_reloc);
571 572 573 574 575
	}

	return 0;
}

576
struct elf *elf_open_read(const char *name, int flags)
577 578
{
	struct elf *elf;
579
	Elf_Cmd cmd;
580 581 582 583 584 585 586 587

	elf_version(EV_CURRENT);

	elf = malloc(sizeof(*elf));
	if (!elf) {
		perror("malloc");
		return NULL;
	}
588
	memset(elf, 0, offsetof(struct elf, sections));
589 590 591

	INIT_LIST_HEAD(&elf->sections);

592 593 594 595
	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 已提交
596
	elf_hash_init(elf->reloc_hash);
597

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

605 606 607 608 609 610 611 612
	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);
613
	if (!elf->elf) {
614
		WARN_ELF("elf_begin");
615 616 617 618
		goto err;
	}

	if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
619
		WARN_ELF("gelf_getehdr");
620 621 622 623 624 625 626 627 628
		goto err;
	}

	if (read_sections(elf))
		goto err;

	if (read_symbols(elf))
		goto err;

M
Matt Helsley 已提交
629
	if (read_relocs(elf))
630 631 632 633 634 635 636 637 638
		goto err;

	return elf;

err:
	elf_close(elf);
	return NULL;
}

639
struct section *elf_create_section(struct elf *elf, const char *name,
640
				   unsigned int sh_flags, size_t entsize, int nr)
641 642 643
{
	struct section *sec, *shstrtab;
	size_t size = entsize * nr;
644
	Elf_Scn *s;
645 646 647 648 649 650 651 652 653 654
	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 已提交
655
	INIT_LIST_HEAD(&sec->reloc_list);
656 657 658 659 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

	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;
700
	sec->sh.sh_flags = SHF_ALLOC | sh_flags;
701 702


703
	/* Add section name to .shstrtab (or .strtab for Clang) */
704
	shstrtab = find_section_by_name(elf, ".shstrtab");
705 706
	if (!shstrtab)
		shstrtab = find_section_by_name(elf, ".strtab");
707
	if (!shstrtab) {
708
		WARN("can't find .shstrtab or .strtab section");
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
		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;

733
	list_add_tail(&sec->list, &elf->sections);
734 735
	elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
	elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
736

737 738
	elf->changed = true;

739 740 741
	return sec;
}

742 743 744 745 746 747 748 749 750 751 752 753 754
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);

755
	sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0);
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
	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)
773
{
M
Matt Helsley 已提交
774
	char *relocname;
775 776
	struct section *sec;

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

785
	sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0);
M
Matt Helsley 已提交
786
	free(relocname);
787 788 789
	if (!sec)
		return NULL;

M
Matt Helsley 已提交
790
	base->reloc = sec;
791 792 793 794 795 796 797 798 799 800 801
	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;
}

802 803 804 805 806 807 808 809 810 811 812 813
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)
814
{
M
Matt Helsley 已提交
815
	struct reloc *reloc;
816
	int idx = 0, size;
817
	void *buf;
818

819
	/* Allocate a buffer for relocations */
820 821 822
	size = nr * sizeof(GElf_Rel);
	buf = malloc(size);
	if (!buf) {
823 824 825 826
		perror("malloc");
		return -1;
	}

827
	sec->data->d_buf = buf;
828
	sec->data->d_size = size;
829
	sec->data->d_type = ELF_T_REL;
830 831 832 833 834

	sec->sh.sh_size = size;

	idx = 0;
	list_for_each_entry(reloc, &sec->reloc_list, list) {
835 836 837
		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);
838 839 840 841 842
		idx++;
	}

	return 0;
}
843

844 845 846 847
static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
{
	struct reloc *reloc;
	int idx = 0, size;
848
	void *buf;
849 850

	/* Allocate a buffer for relocations with addends */
851 852 853
	size = nr * sizeof(GElf_Rela);
	buf = malloc(size);
	if (!buf) {
854 855 856 857
		perror("malloc");
		return -1;
	}

858
	sec->data->d_buf = buf;
859
	sec->data->d_size = size;
860
	sec->data->d_type = ELF_T_RELA;
861 862 863 864

	sec->sh.sh_size = size;

	idx = 0;
M
Matt Helsley 已提交
865
	list_for_each_entry(reloc, &sec->reloc_list, list) {
866 867 868 869
		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);
870 871 872 873 874 875
		idx++;
	}

	return 0;
}

876
int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
877 878 879 880
{
	struct reloc *reloc;
	int nr;

881 882 883
	sec->changed = true;
	elf->changed = true;

884 885 886 887 888 889 890 891 892 893 894
	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;
	}
}

895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
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;
}

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

918 919 920
	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;
921

922 923 924 925 926 927 928 929 930 931 932 933 934
		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;
		}
935 936 937 938 939 940 941
	}

	elf->changed = true;

	return 0;
}

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

947
	/* Update section headers for changed sections: */
948 949 950 951 952 953 954
	list_for_each_entry(sec, &elf->sections, list) {
		if (sec->changed) {
			s = elf_getscn(elf->elf, sec->idx);
			if (!s) {
				WARN_ELF("elf_getscn");
				return -1;
			}
955
			if (!gelf_update_shdr(s, &sec->sh)) {
956 957 958
				WARN_ELF("gelf_update_shdr");
				return -1;
			}
959 960

			sec->changed = false;
961 962 963
		}
	}

964 965 966 967
	/* 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. */
968 969 970 971 972
	if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
		WARN_ELF("elf_update");
		return -1;
	}

973 974
	elf->changed = false;

975 976 977
	return 0;
}

978 979 980 981
void elf_close(struct elf *elf)
{
	struct section *sec, *tmpsec;
	struct symbol *sym, *tmpsym;
M
Matt Helsley 已提交
982
	struct reloc *reloc, *tmpreloc;
983

984 985 986 987 988 989
	if (elf->elf)
		elf_end(elf->elf);

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

990
	list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
991
		list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
992
			list_del(&sym->list);
993
			hash_del(&sym->hash);
994 995
			free(sym);
		}
M
Matt Helsley 已提交
996 997 998 999
		list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
			list_del(&reloc->list);
			hash_del(&reloc->hash);
			free(reloc);
1000 1001 1002 1003
		}
		list_del(&sec->list);
		free(sec);
	}
1004

1005 1006
	free(elf);
}