⛏️ index : haiku.git

/*
 * Copyright 2010, Ithamar R. Adema <ithamar.adema@team-embedded.nl>
 * All rights reserved. Distributed under the terms of the MIT License.
 *
 * Copyright 2009, Johannes Wischert, johanneswi@gmail.com.
 * All rights reserved. Distributed under the terms of the MIT License.
 *
 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
 * All rights reserved. Distributed under the terms of the MIT License.
 *
 * Copyright 2002, Travis Geiselbrecht. All rights reserved.
 * Distributed under the terms of the NewOS License.
 */

#ifdef _BOOT_MODE
#include <boot/arch.h>
#endif

#include <KernelExport.h>

#include <elf_priv.h>
#include <arch/elf.h>


//#define TRACE_ARCH_ELF
#ifdef TRACE_ARCH_ELF
#	define TRACE(x) dprintf x
#	define CHATTY 1
#else
#	define TRACE(x) ;
#	define CHATTY 0
#endif


#ifdef TRACE_ARCH_ELF
static const char *kRelocations[] = {
	"R_ARM_NONE",		//0	Static	Miscellaneous
	"R_ARM_PC24",		//1	Deprecated	ARM	((S + A) | T) ? P
	"R_ARM_ABS32",		//2	Static	Data	(S + A) | T
	"R_ARM_REL32",		//3	Static	Data	((S + A) | T) ? P
	"R_ARM_LDR_PC_G0",	//4	Static	ARM	S + A ? P
	"R_ARM_ABS16",		//5	Static	Data	S + A
	"R_ARM_ABS12",		//6	Static	ARM	S + A
	"R_ARM_THM_ABS5",	//7	Static	Thumb16	S + A
	"R_ARM_ABS8",		//8	Static	Data	S + A
	"R_ARM_SBREL32",	//9	Static	Data	((S + A) | T) ? B(S)
	"R_ARM_THM_CALL",	//10	Static	Thumb32	((S + A) | T) ? P
	"R_ARM_THM_PC8",	//11	Static	Thumb16	S + A ? Pa
	"R_ARM_BREL_ADJ",	//12	Dynamic	Data	?B(S) + A
	"R_ARM_TLS_DESC",	//13	Dynamic	Data
	"R_ARM_THM_SWI8",	//14	Obsolete
	"R_ARM_XPC25",		//15	Obsolete
	"R_ARM_THM_XPC22",	//16	Obsolete	Encodings reserved for future
		// Dynamic relocations
	"R_ARM_TLS_DTPMOD32",	//17	Dynamic	Data	Module[S]
	"R_ARM_TLS_DTPOFF32",	//18	Dynamic	Data	S + A ? TLS
	"R_ARM_TLS_TPOFF32",	//19	Dynamic	Data	S + A ? tp
	"R_ARM_COPY",		//20	Dynamic	Miscellaneous
	"R_ARM_GLOB_DAT",	//21	Dynamic	Data	(S + A) | T
	"R_ARM_JUMP_SLOT",	//22	Dynamic	Data	(S + A) | T
	"R_ARM_RELATIVE",	//23	Dynamic	Data	B(S) + A [Note: see Table 4-16]
	"R_ARM_GOTOFF32",	//24	Static	Data	((S + A) | T) ? GOT_ORG
	"R_ARM_BASE_PREL",	//25	Static	Data	B(S) + A ? P
	"R_ARM_GOT_BREL",	//26	Static	Data	GOT(S) + A ? GOT_ORG
	"R_ARM_PLT32",		//27	Deprecated	ARM	((S + A) | T) ? P
	"R_ARM_CALL",		//28	Static	ARM	((S + A) | T) ? P
	"R_ARM_JUMP24",		//29	Static	ARM	((S + A) | T) ? P
	"R_ARM_THM_JUMP24",	//30	Static	Thumb32	((S + A) | T) ? P
	"R_ARM_BASE_ABS",	//31	Static	Data	B(S) + A
	"R_ARM_ALU_PCREL_7_0",	//32	Obsolete
	"R_ARM_ALU_PCREL_15_8",	//33	Obsolete
	"R_ARM_ALU_PCREL_23_15",	//34	Obsolete	Note ? Legacy (ARM ELF B02)
		// names have been retained for these obsolete relocations.
	"R_ARM_LDR_SBREL_11_0_NC",	//35	Deprecated	ARM	S + A ? B(S)
	"R_ARM_ALU_SBREL_19_12_NC",	//36	Deprecated	ARM	S + A ? B(S)
	"R_ARM_ALU_SBREL_27_20_CK",	//37	Deprecated	ARM	S + A ? B(S)
	"R_ARM_TARGET1",	//38	Static	Miscellaneous	(S + A) | T or ((S + A) | T) ? P
	"R_ARM_SBREL31",	//39	Deprecated	Data	((S + A) | T) ? B(S)
	"R_ARM_V4BX",		//40	Static	Miscellaneous
	"R_ARM_TARGET2",	//41	Static	Miscellaneous
	"R_ARM_PREL31",		//42	Static	Data	((S + A) | T) ? P
	"R_ARM_MOVW_ABS_NC",	//43	Static	ARM	(S + A) | T
	"R_ARM_MOVT_ABS",	//44	Static	ARM	S + A
	"R_ARM_MOVW_PREL_NC",	//45	Static	ARM	((S + A) | T) ? P
	"R_ARM_MOVT_PREL",	//46	Static	ARM	S + A ? P
	"R_ARM_THM_MOVW_ABS_NC",	//47	Static	Thumb32	(S + A) | T
	"R_ARM_THM_MOVT_ABS",	//48	Static	Thumb32	S + A
	"R_ARM_THM_MOVW_PREL_NC",	//49	Static	Thumb32	((S + A) | T) ? P
	"R_ARM_THM_MOVT_PREL",	//50	Static	Thumb32	S + A ? P
	"R_ARM_THM_JUMP19",	//51	Static	Thumb32	((S + A) | T) ? P
	"R_ARM_THM_JUMP6",	//52	Static	Thumb16	S + A ? P
	"R_ARM_THM_ALU_PREL_11_0",	//53	Static	Thumb32	((S + A) | T) ? Pa
	"R_ARM_THM_PC12",	//54	Static	Thumb32	S + A ? Pa
	"R_ARM_ABS32_NOI",	//55	Static	Data	S + A
	"R_ARM_REL32_NOI",	//56	Static	Data	S + A ? P
	"R_ARM_ALU_PC_G0_NC",	//57	Static	ARM	((S + A) | T) ? P
	"R_ARM_ALU_PC_G0",	//58	Static	ARM	((S + A) | T) ? P
	"R_ARM_ALU_PC_G1_NC",	//59	Static	ARM	((S + A) | T) ? P
	"R_ARM_ALU_PC_G1",	//60	Static	ARM	((S + A) | T) ? P
	"R_ARM_ALU_PC_G2",	//61	Static	ARM	((S + A) | T) ? P
	"R_ARM_LDR_PC_G1",	//62	Static	ARM	S + A ? P
	"R_ARM_LDR_PC_G2",	//63	Static	ARM	S + A ? P
	"R_ARM_LDRS_PC_G0",	//64	Static	ARM	S + A ? P
	"R_ARM_LDRS_PC_G1",	//65	Static	ARM	S + A ? P
	"R_ARM_LDRS_PC_G2",	//66	Static	ARM	S + A ? P
	"R_ARM_LDC_PC_G0",	//67	Static	ARM	S + A ? P
	"R_ARM_LDC_PC_G1",	//68	Static	ARM	S + A ? P
	"R_ARM_LDC_PC_G2",	//69	Static	ARM	S + A ? P
	"R_ARM_ALU_SB_G0_NC",	//70	Static	ARM	((S + A) | T) ? B(S)
	"R_ARM_ALU_SB_G0",	//71	Static	ARM	((S + A) | T) ? B(S)
	"R_ARM_ALU_SB_G1_NC",	//72	Static	ARM	((S + A) | T) ? B(S)
	"R_ARM_ALU_SB_G1",	//73	Static	ARM	((S + A) | T) ? B(S)
	"R_ARM_ALU_SB_G2",	//74	Static	ARM	((S + A) | T) ? B(S)
	"R_ARM_LDR_SB_G0",	//75	Static	ARM	S + A ? B(S)
	"R_ARM_LDR_SB_G1",	//76	Static	ARM	S + A ? B(S)
	"R_ARM_LDR_SB_G2",	//77	Static	ARM	S + A ? B(S)
	"R_ARM_LDRS_SB_G0",	//78	Static	ARM	S + A ? B(S)
	"R_ARM_LDRS_SB_G1",	//79	Static	ARM	S + A ? B(S)
	"R_ARM_LDRS_SB_G2",	//80	Static	ARM	S + A ? B(S)
	"R_ARM_LDC_SB_G0",	//81	Static	ARM	S + A ? B(S)
	"R_ARM_LDC_SB_G1",	//82	Static	ARM	S + A ? B(S)
	"R_ARM_LDC_SB_G2",	//83	Static	ARM	S + A ? B(S)
	"R_ARM_MOVW_BREL_NC",	//84	Static	ARM	((S + A) | T) ? B(S)
	"R_ARM_MOVT_BREL",	//85	Static	ARM	S + A ? B(S)
	"R_ARM_MOVW_BREL",	//86	Static	ARM	((S + A) | T) ? B(S)
	"R_ARM_THM_MOVW_BREL_NC",	//87	Static	Thumb32	((S + A) | T) ? B(S)
	"R_ARM_THM_MOVT_BREL",	//88	Static	Thumb32	S + A ? B(S)
	"R_ARM_THM_MOVW_BREL",	//89	Static	Thumb32	((S + A) | T) ? B(S)
	"R_ARM_TLS_GOTDESC",	//90	Static	Data
	"R_ARM_TLS_CALL",	//91	Static	ARM
	"R_ARM_TLS_DESCSEQ",	//92	Static	ARM	TLS relaxation
	"R_ARM_THM_TLS_CALL",	//93	Static	Thumb32
	"R_ARM_PLT32_ABS",	//94	Static	Data	PLT(S) + A
	"R_ARM_GOT_ABS",	//95	Static	Data	GOT(S) + A
	"R_ARM_GOT_PREL",	//96	Static	Data	GOT(S) + A ? P
	"R_ARM_GOT_BREL12",	//97	Static	ARM	GOT(S) + A ? GOT_ORG
	"R_ARM_GOTOFF12",	//98	Static	ARM	S + A ? GOT_ORG
	"R_ARM_GOTRELAX",	//99	Static	Miscellaneous
	"R_ARM_GNU_VTENTRY",	//100	Deprecated	Data	???
	"R_ARM_GNU_VTINHERIT",	//101	Deprecated	Data	???
	"R_ARM_THM_JUMP11",	//102	Static	Thumb16	S + A ? P
	"R_ARM_THM_JUMP8",	//103	Static	Thumb16	S + A ? P
	"R_ARM_TLS_GD32",	//104	Static	Data	GOT(S) + A ? P
	"R_ARM_TLS_LDM32",	//105	Static	Data	GOT(S) + A ? P
	"R_ARM_TLS_LDO32",	//106	Static	Data	S + A ? TLS
	"R_ARM_TLS_IE32",	//107	Static	Data	GOT(S) + A ? P
	"R_ARM_TLS_LE32",	//108	Static	Data	S + A ? tp
	"R_ARM_TLS_LDO12",	//109	Static	ARM	S + A ? TLS
	"R_ARM_TLS_LE12",	//110	Static	ARM	S + A ? tp
	"R_ARM_TLS_IE12GP",	//111	Static	ARM	GOT(S) + A ? GOT_ORG
};
#endif


#ifndef _BOOT_MODE
static bool
is_in_image(struct elf_image_info *image, addr_t address)
{
	return (address >= image->text_region.start
			&& address < image->text_region.start + image->text_region.size)
		|| (address >= image->data_region.start
			&& address < image->data_region.start + image->data_region.size);
}
#endif	// !_BOOT_MODE


#ifdef _BOOT_MODE
status_t
boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel,
	int relLength)
#else
int
arch_elf_relocate_rel(struct elf_image_info *image,
	struct elf_image_info *resolveImage, Elf32_Rel *rel, int relLength)
#endif
{
	elf_addr S;
	addr_t A;
	addr_t P;
	addr_t finalAddress;
	addr_t *resolveAddress;
	int i;

	S = A = P = 0;

	for (i = 0; i * (int)sizeof(Elf32_Rel) < relLength; i++) {
		TRACE(("looking at rel type %s, offset 0x%lx\n",
			kRelocations[ELF32_R_TYPE(rel[i].r_info)], rel[i].r_offset));

		// calc S
		switch (ELF32_R_TYPE(rel[i].r_info)) {
			case R_ARM_JMP_SLOT:
			case R_ARM_GLOB_DAT:
			case R_ARM_ABS32:
			{
				Elf32_Sym *symbol;
				status_t status;

				symbol = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));

#ifdef _BOOT_MODE
				status = boot_elf_resolve_symbol(image, symbol, &S);
#else
				status = elf_resolve_symbol(image, symbol, resolveImage, &S);
#endif
				if (status < B_OK) {
#ifndef _BOOT_MODE
					TRACE(("failed relocating %s\n", SYMNAME(image, symbol)));
#endif
//IRA					return status;
					return B_OK;
				}
#ifndef _BOOT_MODE
				TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol)));
#endif
			}
		}

		// calc A
		switch (ELF32_R_TYPE(rel[i].r_info)) {
			case R_ARM_ABS32:
			case R_ARM_RELATIVE:
#ifndef _BOOT_MODE
				A = *(addr_t *)(image->text_region.delta + rel[i].r_offset);
#else
				A = boot_elf32_get_relocation(image->text_region.delta + rel[i].r_offset);
#endif
				TRACE(("A %p\n", (void *)A));
				break;
		}

		switch (ELF32_R_TYPE(rel[i].r_info)) {
			case R_ARM_NONE:
				continue;
			case R_ARM_RELATIVE:
				// B + A;
				finalAddress = image->text_region.delta + A;
				break;
			case R_ARM_JMP_SLOT:
			case R_ARM_GLOB_DAT:
				finalAddress = S;
				break;
			case R_ARM_ABS32:
				finalAddress = S + A;
				break;
			default:
				dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n",
					ELF32_R_TYPE(rel[i].r_info));
				return B_BAD_DATA;
		}

		resolveAddress = (addr_t *)(image->text_region.delta + rel[i].r_offset);
#ifndef _BOOT_MODE
		if (!is_in_image(image, (addr_t)resolveAddress)) {
			dprintf("arch_elf_relocate_rel: invalid offset %#lx\n",
				rel[i].r_offset);
			return B_BAD_ADDRESS;
		}
		*resolveAddress = finalAddress;
#else
		boot_elf32_set_relocation((Elf32_Addr)resolveAddress, finalAddress);
#endif
		TRACE(("-> offset %#lx = %#lx\n",
			(image->text_region.delta + rel[i].r_offset), finalAddress));
	}

	return B_NO_ERROR;
}


static inline void
write_32(addr_t P, Elf32_Word value)
{
	*(Elf32_Word*)P = value;
}


static inline void
write_16(addr_t P, Elf32_Word value)
{
	// bits 16:29
	*(Elf32_Half*)P = (Elf32_Half)value;
}


static inline bool
write_16_check(addr_t P, Elf32_Word value)
{
	// bits 15:0
	if ((value & 0xffff0000) && (~value & 0xffff8000))
		return false;
	*(Elf32_Half*)P = (Elf32_Half)value;
	return true;
}


static inline bool
write_8(addr_t P, Elf32_Word value)
{
	// bits 7:0
	*(uint8 *)P = (uint8)value;
	return true;
}


static inline bool
write_8_check(addr_t P, Elf32_Word value)
{
	// bits 7:0
	if ((value & 0xffffff00) && (~value & 0xffffff80))
		return false;
	*(uint8 *)P = (uint8)value;
	return true;
}


#ifdef _BOOT_MODE
status_t
boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
	Elf32_Rela *rel, int rel_len)
#else
int
arch_elf_relocate_rela(struct elf_image_info *image,
	struct elf_image_info *resolve_image, Elf32_Rela *rel, int rel_len)
#endif
{
	int i;
	Elf32_Sym *sym;
	int vlErr;
	elf_addr S = 0; // symbol address
	addr_t R = 0;   // section relative symbol address

	addr_t G = 0;   // GOT address
	addr_t L = 0;   // PLT address

	#define P ((addr_t)(image->text_region.delta + rel[i].r_offset))
	#define A ((addr_t)rel[i].r_addend)
	#define B (image->text_region.delta)
	#warning ARM:define T correctly for thumb!!!
	#define	T 0

	// TODO: Get the GOT address!
	#define REQUIRE_GOT     \
		if (G == 0) {   \
			dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
			return B_ERROR; \
		}

	// TODO: Get the PLT address!
	#define REQUIRE_PLT     \
	if (L == 0) {   \
		dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
		return B_ERROR; \
	}

	for (i = 0; i * (int)sizeof(Elf32_Rela) < rel_len; i++) {
		#if CHATTY
		dprintf("looking at rel type %d, offset 0x%lx, "
		"sym 0x%lx, addend 0x%lx\n", ELF32_R_TYPE(rel[i].r_info),
		rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
		#endif
		switch (ELF32_R_TYPE(rel[i].r_info)) {
		#warning ARM:ADDOTHERREL
			case R_ARM_GLOB_DAT:
				sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));

				#ifdef _BOOT_MODE
				vlErr = boot_elf_resolve_symbol(image, sym, &S);
				#else
				vlErr = elf_resolve_symbol(image, sym, resolve_image, &S);
				#endif
				if (vlErr < 0) {
					dprintf("%s(): Failed to relocate "
						"entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, "
						"addend 0x%lx\n", __FUNCTION__, i,
						ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset,
						ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
					return vlErr;
				}
				break;
		}

		#warning ARM:ADDOTHERREL
		switch (ELF32_R_TYPE(rel[i].r_info)) {
			case R_ARM_GLOB_DAT:
				write_32(P, (S + A) | T);
				break;

			case R_ARM_NONE:
				break;

			default:
				dprintf("arch_elf_relocate_rela(): unhandled "
					"relocation type %d!\n", ELF32_R_TYPE(rel[i].r_info));
				return B_ERROR;
		}
	}

	#warning ARM: FIXME!!!!!!!
	return B_NO_ERROR;
}