arch/loongarch/kernel/module.c

Source file repositories/reference/linux-study-clean/arch/loongarch/kernel/module.c

File Facts

System
Linux kernel
Corpus path
arch/loongarch/kernel/module.c
Extension
.c
Size
17959 bytes
Lines
634
Domain
Architecture Layer
Bucket
arch/loongarch
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (IS_ERR_VALUE(sym->st_value)) {
			/* Ignore unresolved weak symbol */
			if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
				continue;
			pr_warn("%s: Unknown symbol %s\n", mod->name, strtab + sym->st_name);
			return -ENOENT;
		}

		type = ELF_R_TYPE(rel[i].r_info);

		if (type < ARRAY_SIZE(reloc_rela_handlers))
			handler = reloc_rela_handlers[type];
		else
			handler = NULL;

		if (!handler) {
			pr_err("%s: Unknown relocation type %u\n", mod->name, type);
			return -EINVAL;
		}

		pr_debug("type %d st_value %lx r_addend %lx loc %lx\n",
		       (int)ELF_R_TYPE(rel[i].r_info),
		       (unsigned long)sym->st_value, (unsigned long)rel[i].r_addend, (unsigned long)location);

		v = sym->st_value + rel[i].r_addend;

		if (type == R_LARCH_PCADD_LO12 || type == R_LARCH_GOT_PCADD_LO12) {
			bool found = false;
			unsigned int j = idx;

			do {
				u32 hi20_type = ELF_R_TYPE(rel[j].r_info);
				unsigned long hi20_location =
					sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[j].r_offset;

				/* Find the corresponding HI20 relocation entry */
				if ((hi20_location == sym->st_value) && (hi20_type == type - 1)) {
					s32 hi20, lo12;
					Elf_Sym *hi20_sym =
						(Elf_Sym *)sechdrs[symindex].sh_addr + ELF_R_SYM(rel[j].r_info);
					unsigned long hi20_sym_val = hi20_sym->st_value + rel[j].r_addend;

					/* Calculate LO12 offset */
					size_t offset = hi20_sym_val - hi20_location;
					if (hi20_type == R_LARCH_GOT_PCADD_HI20) {
						offset = module_emit_got_entry(mod, sechdrs, hi20_sym_val);
						offset = offset - hi20_location;
					}
					hi20 = (offset + 0x800) & 0xfffff000;
					v = lo12 = offset - hi20;
					found = true;
					break;
				}

				j = (j + 1) % num_relocations;

			} while (idx != j);

			if (!found) {
				pr_err("%s: Can not find HI20 relocation information\n", mod->name);
				return -EINVAL;
			}

			idx = j; /* Record the previous j-loop end index */
		}

		switch (type) {
		case R_LARCH_B26:
			err = apply_r_larch_b26(mod, sechdrs, location,
						     v, rela_stack, &rela_stack_top, type);
			break;
		case R_LARCH_GOT_PC_HI20...R_LARCH_GOT_PC_LO12:
		case R_LARCH_GOT_PCADD_HI20...R_LARCH_GOT_PCADD_LO12:
			err = apply_r_larch_got_pc(mod, sechdrs, location,
						     v, rela_stack, &rela_stack_top, type);
			break;
		case R_LARCH_SOP_PUSH_PLT_PCREL:
			err = apply_r_larch_sop_push_plt_pcrel(mod, sechdrs, location,
						     v, rela_stack, &rela_stack_top, type);
			break;
		default:
			err = handler(mod, location, v, rela_stack, &rela_stack_top, type);
		}
		if (err)
			return err;
	}

	return 0;
}

Annotation

Implementation Notes