riscv: tools: Prelink u-boot
Add prelink-riscv to arrange .rela.dyn and .rela.got in compile time. So that u-boot can be directly executed without fixup. Signed-off-by: Chih-Mao Chen <cmchen@andestech.com> Signed-off-by: Rick Chen <rick@andestech.com> Signed-off-by: Rick Chen <rickchen36@gmail.com> Signed-off-by: Greentime Hu <green.hu@gmail.com>
This commit is contained in:
		
							parent
							
								
									3dafc016c1
								
							
						
					
					
						commit
						42ac26f2b0
					
				
							
								
								
									
										4
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										4
									
								
								Makefile
								
								
								
								
							|  | @ -1264,6 +1264,10 @@ ifeq ($(CONFIG_KALLSYMS),y) | ||||||
| 	$(call cmd,u-boot__) common/system_map.o | 	$(call cmd,u-boot__) common/system_map.o | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
|  | ifeq ($(CONFIG_RISCV),y) | ||||||
|  | 	@tools/prelink-riscv $@ 0 | ||||||
|  | endif | ||||||
|  | 
 | ||||||
| quiet_cmd_sym ?= SYM     $@ | quiet_cmd_sym ?= SYM     $@ | ||||||
|       cmd_sym ?= $(OBJDUMP) -t $< > $@ |       cmd_sym ?= $(OBJDUMP) -t $< > $@ | ||||||
| u-boot.sym: u-boot FORCE | u-boot.sym: u-boot FORCE | ||||||
|  |  | ||||||
|  | @ -185,6 +185,7 @@ hostprogs-$(CONFIG_KIRKWOOD) += kwboot | ||||||
| hostprogs-$(CONFIG_ARCH_MVEBU) += kwboot | hostprogs-$(CONFIG_ARCH_MVEBU) += kwboot | ||||||
| hostprogs-y += proftool | hostprogs-y += proftool | ||||||
| hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela | hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela | ||||||
|  | hostprogs-$(CONFIG_RISCV) += prelink-riscv | ||||||
| 
 | 
 | ||||||
| hostprogs-y += fdtgrep | hostprogs-y += fdtgrep | ||||||
| fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o | fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o | ||||||
|  |  | ||||||
|  | @ -0,0 +1,102 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2017 Andes Technology | ||||||
|  |  * Chih-Mao Chen <cmchen@andestech.com> | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier:     GPL-2.0+ | ||||||
|  |  * | ||||||
|  |  * Statically process runtime relocations on RISC-V ELF images | ||||||
|  |  * so that it can be directly executed when loaded at LMA | ||||||
|  |  * without fixup. Both RV32 and RV64 are supported. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ | ||||||
|  | #error "Only little-endian host is supported" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <errno.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | #include <elf.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <sys/mman.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | 
 | ||||||
|  | #ifndef EM_RISCV | ||||||
|  | #define EM_RISCV 243 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef R_RISCV_32 | ||||||
|  | #define R_RISCV_32 1 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef R_RISCV_64 | ||||||
|  | #define R_RISCV_64 2 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef R_RISCV_RELATIVE | ||||||
|  | #define R_RISCV_RELATIVE 3 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | const char *argv0; | ||||||
|  | 
 | ||||||
|  | #define die(fmt, ...) \ | ||||||
|  | 	do { \ | ||||||
|  | 		fprintf(stderr, "%s: " fmt "\n", argv0, ## __VA_ARGS__); \ | ||||||
|  | 		exit(EXIT_FAILURE); \ | ||||||
|  | 	} while (0) | ||||||
|  | 
 | ||||||
|  | #define PRELINK_INC_BITS 32 | ||||||
|  | #include "prelink-riscv.inc" | ||||||
|  | #undef PRELINK_INC_BITS | ||||||
|  | 
 | ||||||
|  | #define PRELINK_INC_BITS 64 | ||||||
|  | #include "prelink-riscv.inc" | ||||||
|  | #undef PRELINK_INC_BITS | ||||||
|  | 
 | ||||||
|  | int main(int argc, const char *const *argv) | ||||||
|  | { | ||||||
|  | 	argv0 = argv[0]; | ||||||
|  | 
 | ||||||
|  | 	if (argc < 2) { | ||||||
|  | 		fprintf(stderr, "Usage: %s <u-boot>\n", argv0); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	int fd = open(argv[1], O_RDWR, 0); | ||||||
|  | 
 | ||||||
|  | 	if (fd < 0) | ||||||
|  | 		die("Cannot open %s: %s", argv[1], strerror(errno)); | ||||||
|  | 
 | ||||||
|  | 	struct stat st; | ||||||
|  | 
 | ||||||
|  | 	if (fstat(fd, &st) < 0) | ||||||
|  | 		die("Cannot stat %s: %s", argv[1], strerror(errno)); | ||||||
|  | 
 | ||||||
|  | 	void *data = | ||||||
|  | 		mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||||||
|  | 
 | ||||||
|  | 	if (data == MAP_FAILED) | ||||||
|  | 		die("Cannot mmap %s: %s", argv[1], strerror(errno)); | ||||||
|  | 
 | ||||||
|  | 	close(fd); | ||||||
|  | 
 | ||||||
|  | 	unsigned char *e_ident = (unsigned char *)data; | ||||||
|  | 
 | ||||||
|  | 	if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) | ||||||
|  | 		die("Invalid ELF file %s", argv[1]); | ||||||
|  | 
 | ||||||
|  | 	bool is64 = e_ident[EI_CLASS] == ELFCLASS64; | ||||||
|  | 
 | ||||||
|  | 	if (is64) | ||||||
|  | 		prelink64(data); | ||||||
|  | 	else | ||||||
|  | 		prelink32(data); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,112 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (C) 2017 Andes Technology | ||||||
|  |  * Chih-Mao Chen <cmchen@andestech.com> | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier:     GPL-2.0+ | ||||||
|  |  * | ||||||
|  |  * Statically process runtime relocations on RISC-V ELF images | ||||||
|  |  * so that it can be directly executed when loaded at LMA | ||||||
|  |  * without fixup. Both RV32 and RV64 are supported. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define CONCAT_IMPL(x, y) x##y
 | ||||||
|  | #define CONCAT(x, y) CONCAT_IMPL(x, y)
 | ||||||
|  | #define CONCAT3(x, y, z) CONCAT(CONCAT(x, y), z)
 | ||||||
|  | 
 | ||||||
|  | #define prelink_nn      CONCAT(prelink, PRELINK_INC_BITS)
 | ||||||
|  | #define uintnn_t        CONCAT3(uint, PRELINK_INC_BITS, _t)
 | ||||||
|  | #define get_offset_nn   CONCAT(get_offset_, PRELINK_INC_BITS)
 | ||||||
|  | #define Elf_Ehdr        CONCAT3(Elf, PRELINK_INC_BITS, _Ehdr)
 | ||||||
|  | #define Elf_Phdr        CONCAT3(Elf, PRELINK_INC_BITS, _Phdr)
 | ||||||
|  | #define Elf_Rela        CONCAT3(Elf, PRELINK_INC_BITS, _Rela)
 | ||||||
|  | #define Elf_Sym         CONCAT3(Elf, PRELINK_INC_BITS, _Sym)
 | ||||||
|  | #define Elf_Dyn         CONCAT3(Elf, PRELINK_INC_BITS, _Dyn)
 | ||||||
|  | #define Elf_Addr        CONCAT3(Elf, PRELINK_INC_BITS, _Addr)
 | ||||||
|  | #define ELF_R_TYPE      CONCAT3(ELF, PRELINK_INC_BITS, _R_TYPE)
 | ||||||
|  | #define ELF_R_SYM       CONCAT3(ELF, PRELINK_INC_BITS, _R_SYM)
 | ||||||
|  | 
 | ||||||
|  | static void* get_offset_nn (void* data, Elf_Phdr* phdrs, size_t phnum, Elf_Addr addr) | ||||||
|  | { | ||||||
|  | 	Elf_Phdr *p; | ||||||
|  | 
 | ||||||
|  | 	for (p = phdrs; p < phdrs + phnum; ++p) | ||||||
|  | 		if (p->p_vaddr <= addr && p->p_vaddr + p->p_memsz > addr) | ||||||
|  | 			return data + p->p_offset + (addr - p->p_vaddr); | ||||||
|  | 
 | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void prelink_nn(void *data) | ||||||
|  | { | ||||||
|  | 	Elf_Ehdr *ehdr = data; | ||||||
|  | 	Elf_Phdr *p; | ||||||
|  | 	Elf_Dyn *dyn; | ||||||
|  | 	Elf_Rela *r; | ||||||
|  | 
 | ||||||
|  | 	if (ehdr->e_machine != EM_RISCV) | ||||||
|  | 		die("Machine type is not RISC-V"); | ||||||
|  | 
 | ||||||
|  | 	Elf_Phdr *phdrs = data + ehdr->e_phoff; | ||||||
|  | 
 | ||||||
|  | 	Elf_Dyn *dyns = NULL; | ||||||
|  | 	for (p = phdrs; p < phdrs + ehdr->e_phnum; ++p) { | ||||||
|  | 		if (p->p_type == PT_DYNAMIC) { | ||||||
|  | 			dyns = data + p->p_offset; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (dyns == NULL) | ||||||
|  | 		die("No dynamic section found"); | ||||||
|  | 
 | ||||||
|  | 	Elf_Rela *rela_dyn = NULL; | ||||||
|  | 	size_t rela_count = 0; | ||||||
|  | 	Elf_Sym *dynsym = NULL; | ||||||
|  | 	for (dyn = dyns;; ++dyn) { | ||||||
|  | 		if (dyn->d_tag == DT_NULL) | ||||||
|  | 			break; | ||||||
|  | 		else if (dyn->d_tag == DT_RELA) | ||||||
|  | 			rela_dyn = get_offset_nn(data, phdrs, ehdr->e_phnum, + dyn->d_un.d_ptr); | ||||||
|  | 		else if (dyn->d_tag == DT_RELASZ) | ||||||
|  | 			rela_count = dyn->d_un.d_val / sizeof(Elf_Rela); | ||||||
|  | 		else if (dyn->d_tag == DT_SYMTAB) | ||||||
|  | 			dynsym = get_offset_nn(data, phdrs, ehdr->e_phnum, + dyn->d_un.d_ptr); | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (rela_dyn == NULL) | ||||||
|  | 		die("No .rela.dyn found"); | ||||||
|  | 
 | ||||||
|  | 	if (dynsym == NULL) | ||||||
|  | 		die("No .dynsym found"); | ||||||
|  | 
 | ||||||
|  | 	for (r = rela_dyn; r < rela_dyn + rela_count; ++r) { | ||||||
|  | 		void* buf = get_offset_nn(data, phdrs, ehdr->e_phnum, r->r_offset); | ||||||
|  | 
 | ||||||
|  | 		if (buf == NULL) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		if (ELF_R_TYPE(r->r_info) == R_RISCV_RELATIVE) | ||||||
|  | 			*((uintnn_t*) buf) = r->r_addend; | ||||||
|  | 		else if (ELF_R_TYPE(r->r_info) == R_RISCV_32) | ||||||
|  | 			*((uint32_t*) buf) = dynsym[ELF_R_SYM(r->r_info)].st_value; | ||||||
|  | 		else if (ELF_R_TYPE(r->r_info) == R_RISCV_64) | ||||||
|  | 			*((uint64_t*) buf) = dynsym[ELF_R_SYM(r->r_info)].st_value; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #undef prelink_nn
 | ||||||
|  | #undef uintnn_t
 | ||||||
|  | #undef get_offset_nn
 | ||||||
|  | #undef Elf_Ehdr
 | ||||||
|  | #undef Elf_Phdr
 | ||||||
|  | #undef Elf_Rela
 | ||||||
|  | #undef Elf_Sym
 | ||||||
|  | #undef Elf_Dyn
 | ||||||
|  | #undef Elf_Addr
 | ||||||
|  | #undef ELF_R_TYPE
 | ||||||
|  | #undef ELF_R_SYM
 | ||||||
|  | 
 | ||||||
|  | #undef CONCAT_IMPL
 | ||||||
|  | #undef CONCAT
 | ||||||
|  | #undef CONCAT3
 | ||||||
		Loading…
	
		Reference in New Issue