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

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)) {
222
		WARN_ELF("elf_getshdrnum");
223 224 225 226
		return -1;
	}

	if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
227
		WARN_ELF("elf_getshdrstrndx");
228 229 230 231 232 233 234 235 236 237 238
		return -1;
	}

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

239
		INIT_LIST_HEAD(&sec->symbol_list);
M
Matt Helsley 已提交
240
		INIT_LIST_HEAD(&sec->reloc_list);
241 242 243

		s = elf_getscn(elf->elf, i);
		if (!s) {
244
			WARN_ELF("elf_getscn");
245 246 247 248 249 250
			return -1;
		}

		sec->idx = elf_ndxscn(s);

		if (!gelf_getshdr(s, &sec->sh)) {
251
			WARN_ELF("gelf_getshdr");
252 253 254 255 256
			return -1;
		}

		sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
		if (!sec->name) {
257
			WARN_ELF("elf_strptr");
258 259 260
			return -1;
		}

261 262 263 264 265 266 267 268 269 270 271 272
		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;
			}
273
		}
274
		sec->len = sec->sh.sh_size;
275 276

		list_add_tail(&sec->list, &elf->sections);
277 278
		elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
		elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
279 280
	}

P
Peter Zijlstra 已提交
281 282 283
	if (stats)
		printf("nr_sections: %lu\n", (unsigned long)sections_nr);

284 285 286 287 288 289 290 291 292 293 294
	/* 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)
{
295
	struct section *symtab, *symtab_shndx, *sec;
296 297 298
	struct symbol *sym, *pfunc;
	struct list_head *entry;
	struct rb_node *pnode;
299
	int symbols_nr, i;
300
	char *coldstr;
301 302
	Elf_Data *shndx_data = NULL;
	Elf32_Word shndx;
303 304 305

	symtab = find_section_by_name(elf, ".symtab");
	if (!symtab) {
306 307 308 309 310
		/*
		 * A missing symbol table is actually possible if it's an empty
		 * .o file.  This can happen for thunk_64.o.
		 */
		return 0;
311 312
	}

313 314 315 316
	symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
	if (symtab_shndx)
		shndx_data = symtab_shndx->data;

317 318 319 320 321 322 323 324 325
	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));
326
		sym->alias = sym;
327 328 329

		sym->idx = i;

330 331 332
		if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
				      &shndx)) {
			WARN_ELF("gelf_getsymshndx");
333 334 335 336 337 338
			goto err;
		}

		sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
				       sym->sym.st_name);
		if (!sym->name) {
339
			WARN_ELF("elf_strptr");
340 341 342 343 344 345
			goto err;
		}

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

346 347 348 349 350 351 352
		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);
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
			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;

368
		rb_add(&sym->node, &sym->sec->symbol_tree, symbol_to_offset);
369 370 371 372 373
		pnode = rb_prev(&sym->node);
		if (pnode)
			entry = &rb_entry(pnode, struct symbol, node)->list;
		else
			entry = &sym->sec->symbol_list;
374
		list_add(&sym->list, entry);
375 376
		elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
		elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
377 378 379 380 381 382 383

		/*
		 * 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);
384 385
	}

P
Peter Zijlstra 已提交
386 387 388
	if (stats)
		printf("nr_symbols: %lu\n", (unsigned long)symbols_nr);

389 390 391
	/* 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) {
392 393
			char pname[MAX_NAME_LEN + 1];
			size_t pnamelen;
394 395
			if (sym->type != STT_FUNC)
				continue;
396 397 398 399 400 401 402

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

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

403
			coldstr = strstr(sym->name, ".cold");
404 405 406
			if (!coldstr)
				continue;

407 408 409 410 411 412 413 414 415 416
			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);
417 418 419 420

			if (!pfunc) {
				WARN("%s(): can't find parent function",
				     sym->name);
421
				return -1;
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
			}

			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;
439 440 441 442
			}
		}
	}

443 444 445 446 447 448 449
	return 0;

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

450 451 452 453
static struct section *elf_create_reloc_section(struct elf *elf,
						struct section *base,
						int reltype);

454 455
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
		  unsigned int type, struct symbol *sym, int addend)
456
{
457 458
	struct reloc *reloc;

459 460 461
	if (!sec->reloc && !elf_create_reloc_section(elf, sec, SHT_RELA))
		return -1;

462 463 464 465 466 467 468 469 470 471 472 473
	reloc = malloc(sizeof(*reloc));
	if (!reloc) {
		perror("malloc");
		return -1;
	}
	memset(reloc, 0, sizeof(*reloc));

	reloc->sec = sec->reloc;
	reloc->offset = offset;
	reloc->type = type;
	reloc->sym = sym;
	reloc->addend = addend;
474

475
	list_add_tail(&reloc->list, &sec->reloc->reloc_list);
M
Matt Helsley 已提交
476
	elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
477

478 479 480 481 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 510 511 512 513 514 515 516
	sec->reloc->changed = true;

	return 0;
}

int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
			  unsigned long offset, unsigned int type,
			  struct section *insn_sec, unsigned long insn_off)
{
	struct symbol *sym;
	int addend;

	if (insn_sec->sym) {
		sym = insn_sec->sym;
		addend = insn_off;

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

		if (!sym) {
			WARN("can't find symbol containing %s+0x%lx", insn_sec->name, insn_off);
			return -1;
		}

		addend = insn_off - sym->offset;
	}

	return elf_add_reloc(elf, sec, offset, type, sym, addend);
517 518
}

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
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 已提交
545
static int read_relocs(struct elf *elf)
546 547
{
	struct section *sec;
M
Matt Helsley 已提交
548
	struct reloc *reloc;
549 550
	int i;
	unsigned int symndx;
M
Matt Helsley 已提交
551
	unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0;
552 553

	list_for_each_entry(sec, &elf->sections, list) {
554 555
		if ((sec->sh.sh_type != SHT_RELA) &&
		    (sec->sh.sh_type != SHT_REL))
556 557
			continue;

558
		sec->base = find_section_by_index(elf, sec->sh.sh_info);
559
		if (!sec->base) {
M
Matt Helsley 已提交
560
			WARN("can't find base section for reloc section %s",
561 562 563 564
			     sec->name);
			return -1;
		}

M
Matt Helsley 已提交
565
		sec->base->reloc = sec;
566

M
Matt Helsley 已提交
567
		nr_reloc = 0;
568
		for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
M
Matt Helsley 已提交
569 570
			reloc = malloc(sizeof(*reloc));
			if (!reloc) {
571 572 573
				perror("malloc");
				return -1;
			}
M
Matt Helsley 已提交
574
			memset(reloc, 0, sizeof(*reloc));
575 576 577 578 579 580 581 582 583 584
			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;
585 586
			}

M
Matt Helsley 已提交
587
			reloc->sec = sec;
588 589
			reloc->idx = i;
			reloc->sym = find_symbol_by_index(elf, symndx);
M
Matt Helsley 已提交
590 591
			if (!reloc->sym) {
				WARN("can't find reloc entry symbol %d for %s",
592 593 594
				     symndx, sec->name);
				return -1;
			}
595

596 597 598
			list_add_tail(&reloc->list, &sec->reloc_list);
			elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));

M
Matt Helsley 已提交
599
			nr_reloc++;
600
		}
M
Matt Helsley 已提交
601 602
		max_reloc = max(max_reloc, nr_reloc);
		tot_reloc += nr_reloc;
P
Peter Zijlstra 已提交
603 604 605
	}

	if (stats) {
M
Matt Helsley 已提交
606 607
		printf("max_reloc: %lu\n", max_reloc);
		printf("tot_reloc: %lu\n", tot_reloc);
608 609 610 611 612
	}

	return 0;
}

613
struct elf *elf_open_read(const char *name, int flags)
614 615
{
	struct elf *elf;
616
	Elf_Cmd cmd;
617 618 619 620 621 622 623 624

	elf_version(EV_CURRENT);

	elf = malloc(sizeof(*elf));
	if (!elf) {
		perror("malloc");
		return NULL;
	}
625
	memset(elf, 0, offsetof(struct elf, sections));
626 627 628

	INIT_LIST_HEAD(&elf->sections);

629 630 631 632
	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 已提交
633
	elf_hash_init(elf->reloc_hash);
634

635
	elf->fd = open(name, flags);
636
	if (elf->fd == -1) {
637 638
		fprintf(stderr, "objtool: Can't open '%s': %s\n",
			name, strerror(errno));
639 640 641
		goto err;
	}

642 643 644 645 646 647 648 649
	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);
650
	if (!elf->elf) {
651
		WARN_ELF("elf_begin");
652 653 654 655
		goto err;
	}

	if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
656
		WARN_ELF("gelf_getehdr");
657 658 659 660 661 662 663 664 665
		goto err;
	}

	if (read_sections(elf))
		goto err;

	if (read_symbols(elf))
		goto err;

M
Matt Helsley 已提交
666
	if (read_relocs(elf))
667 668 669 670 671 672 673 674 675
		goto err;

	return elf;

err:
	elf_close(elf);
	return NULL;
}

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 704 705 706 707 708 709 710 711
static int elf_add_string(struct elf *elf, struct section *strtab, char *str)
{
	Elf_Data *data;
	Elf_Scn *s;
	int len;

	if (!strtab)
		strtab = find_section_by_name(elf, ".strtab");
	if (!strtab) {
		WARN("can't find .strtab section");
		return -1;
	}

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

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

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

	len = strtab->len;
	strtab->len += data->d_size;
	strtab->changed = true;

	return len;
}

712
struct section *elf_create_section(struct elf *elf, const char *name,
713
				   unsigned int sh_flags, size_t entsize, int nr)
714 715 716
{
	struct section *sec, *shstrtab;
	size_t size = entsize * nr;
717
	Elf_Scn *s;
718 719 720 721 722 723 724 725 726

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

	INIT_LIST_HEAD(&sec->symbol_list);
M
Matt Helsley 已提交
727
	INIT_LIST_HEAD(&sec->reloc_list);
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771

	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;
772
	sec->sh.sh_flags = SHF_ALLOC | sh_flags;
773

774
	/* Add section name to .shstrtab (or .strtab for Clang) */
775
	shstrtab = find_section_by_name(elf, ".shstrtab");
776 777
	if (!shstrtab)
		shstrtab = find_section_by_name(elf, ".strtab");
778
	if (!shstrtab) {
779
		WARN("can't find .shstrtab or .strtab section");
780 781
		return NULL;
	}
782 783
	sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
	if (sec->sh.sh_name == -1)
784 785
		return NULL;

786
	list_add_tail(&sec->list, &elf->sections);
787 788
	elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
	elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
789

790 791
	elf->changed = true;

792 793 794
	return sec;
}

795 796 797 798 799 800 801 802 803 804 805 806 807
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);

808
	sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0);
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
	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)
826
{
M
Matt Helsley 已提交
827
	char *relocname;
828 829
	struct section *sec;

M
Matt Helsley 已提交
830 831
	relocname = malloc(strlen(base->name) + strlen(".rela") + 1);
	if (!relocname) {
832 833 834
		perror("malloc");
		return NULL;
	}
M
Matt Helsley 已提交
835 836
	strcpy(relocname, ".rela");
	strcat(relocname, base->name);
837

838
	sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0);
M
Matt Helsley 已提交
839
	free(relocname);
840 841 842
	if (!sec)
		return NULL;

M
Matt Helsley 已提交
843
	base->reloc = sec;
844 845 846 847 848 849 850 851 852 853 854
	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;
}

855
static struct section *elf_create_reloc_section(struct elf *elf,
856 857 858 859 860 861 862 863 864 865 866
					 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)
867
{
M
Matt Helsley 已提交
868
	struct reloc *reloc;
869
	int idx = 0, size;
870
	void *buf;
871

872
	/* Allocate a buffer for relocations */
873 874 875
	size = nr * sizeof(GElf_Rel);
	buf = malloc(size);
	if (!buf) {
876 877 878 879
		perror("malloc");
		return -1;
	}

880
	sec->data->d_buf = buf;
881
	sec->data->d_size = size;
882
	sec->data->d_type = ELF_T_REL;
883 884 885 886 887

	sec->sh.sh_size = size;

	idx = 0;
	list_for_each_entry(reloc, &sec->reloc_list, list) {
888 889 890
		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);
891 892 893 894 895
		idx++;
	}

	return 0;
}
896

897 898 899 900
static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
{
	struct reloc *reloc;
	int idx = 0, size;
901
	void *buf;
902 903

	/* Allocate a buffer for relocations with addends */
904 905 906
	size = nr * sizeof(GElf_Rela);
	buf = malloc(size);
	if (!buf) {
907 908 909 910
		perror("malloc");
		return -1;
	}

911
	sec->data->d_buf = buf;
912
	sec->data->d_size = size;
913
	sec->data->d_type = ELF_T_RELA;
914 915 916 917

	sec->sh.sh_size = size;

	idx = 0;
M
Matt Helsley 已提交
918
	list_for_each_entry(reloc, &sec->reloc_list, list) {
919 920 921 922
		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);
923 924 925 926 927 928
		idx++;
	}

	return 0;
}

929
static int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
{
	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;
	}
}

945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
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;
}

964
int elf_write_reloc(struct elf *elf, struct reloc *reloc)
965
{
966
	struct section *sec = reloc->sec;
967

968 969 970
	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;
971

972 973 974 975 976 977 978 979 980 981 982 983 984
		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;
		}
985 986 987 988 989 990 991
	}

	elf->changed = true;

	return 0;
}

992
int elf_write(struct elf *elf)
993 994 995 996
{
	struct section *sec;
	Elf_Scn *s;

997
	/* Update changed relocation sections and section headers: */
998 999
	list_for_each_entry(sec, &elf->sections, list) {
		if (sec->changed) {
1000 1001 1002 1003 1004 1005
			if (sec->base &&
			    elf_rebuild_reloc_section(elf, sec)) {
				WARN("elf_rebuild_reloc_section");
				return -1;
			}

1006 1007 1008 1009 1010
			s = elf_getscn(elf->elf, sec->idx);
			if (!s) {
				WARN_ELF("elf_getscn");
				return -1;
			}
1011
			if (!gelf_update_shdr(s, &sec->sh)) {
1012 1013 1014
				WARN_ELF("gelf_update_shdr");
				return -1;
			}
1015 1016

			sec->changed = false;
1017
			elf->changed = true;
1018 1019 1020
		}
	}

1021 1022 1023 1024
	/* 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. */
1025 1026 1027 1028 1029
	if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
		WARN_ELF("elf_update");
		return -1;
	}

1030 1031
	elf->changed = false;

1032 1033 1034
	return 0;
}

1035 1036 1037 1038
void elf_close(struct elf *elf)
{
	struct section *sec, *tmpsec;
	struct symbol *sym, *tmpsym;
M
Matt Helsley 已提交
1039
	struct reloc *reloc, *tmpreloc;
1040

1041 1042 1043 1044 1045 1046
	if (elf->elf)
		elf_end(elf->elf);

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

1047
	list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
1048
		list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
1049
			list_del(&sym->list);
1050
			hash_del(&sym->hash);
1051 1052
			free(sym);
		}
M
Matt Helsley 已提交
1053 1054 1055 1056
		list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
			list_del(&reloc->list);
			hash_del(&reloc->hash);
			free(reloc);
1057 1058 1059 1060
		}
		list_del(&sec->list);
		free(sec);
	}
1061

1062 1063
	free(elf);
}