tools/objtool/special.c

Source file repositories/reference/linux-study-clean/tools/objtool/special.c

File Facts

System
Linux kernel
Corpus path
tools/objtool/special.c
Extension
.c
Size
3953 bytes
Lines
170
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct special_entry {
	const char *sec;
	bool group, jump_or_nop;
	unsigned char size, orig, new;
	unsigned char orig_len, new_len; /* group only */
	unsigned char feature; /* ALTERNATIVE macro CPU feature */
	unsigned char key; /* jump_label key */
};

static const struct special_entry entries[] = {
	{
		.sec = ".altinstructions",
		.group = true,
		.size = ALT_ENTRY_SIZE,
		.orig = ALT_ORIG_OFFSET,
		.orig_len = ALT_ORIG_LEN_OFFSET,
		.new = ALT_NEW_OFFSET,
		.new_len = ALT_NEW_LEN_OFFSET,
		.feature = ALT_FEATURE_OFFSET,
	},
	{
		.sec = "__jump_table",
		.jump_or_nop = true,
		.size = JUMP_ENTRY_SIZE,
		.orig = JUMP_ORIG_OFFSET,
		.new = JUMP_NEW_OFFSET,
		.key = JUMP_KEY_OFFSET,
	},
	{
		.sec = "__ex_table",
		.size = EX_ENTRY_SIZE,
		.orig = EX_ORIG_OFFSET,
		.new = EX_NEW_OFFSET,
	},
	{},
};

void __weak arch_handle_alternative(struct special_alt *alt)
{
}

static void reloc_to_sec_off(struct reloc *reloc, struct section **sec,
			     unsigned long *off)
{
	*sec = reloc->sym->sec;
	*off = reloc->sym->offset + reloc_addend(reloc);
}

static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
			 struct section *sec, int idx,
			 struct special_alt *alt)
{
	struct reloc *orig_reloc, *new_reloc;
	unsigned long offset;

	offset = idx * entry->size;

	alt->group = entry->group;
	alt->jump_or_nop = entry->jump_or_nop;

	if (alt->group) {
		alt->orig_len = *(unsigned char *)(sec->data->d_buf + offset +
						   entry->orig_len);
		alt->new_len = *(unsigned char *)(sec->data->d_buf + offset +
						  entry->new_len);
		alt->feature = *(unsigned int *)(sec->data->d_buf + offset +
						 entry->feature);
	}

	orig_reloc = find_reloc_by_dest(elf, sec, offset + entry->orig);
	if (!orig_reloc) {
		ERROR_FUNC(sec, offset + entry->orig, "can't find orig reloc");
		return -1;
	}

	reloc_to_sec_off(orig_reloc, &alt->orig_sec, &alt->orig_off);

	arch_handle_alternative(alt);

	if (!entry->group || alt->new_len) {
		new_reloc = find_reloc_by_dest(elf, sec, offset + entry->new);
		if (!new_reloc) {
			ERROR_FUNC(sec, offset + entry->new, "can't find new reloc");
			return -1;
		}

		reloc_to_sec_off(new_reloc, &alt->new_sec, &alt->new_off);

		/* _ASM_EXTABLE_EX hack */
		if (alt->new_off >= 0x7ffffff0)

Annotation

Implementation Notes