| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (C) 2023 - Google LLC
- * Author: Ard Biesheuvel <ardb@google.com>
- */
- #include <elf.h>
- #include <fcntl.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- #define HOST_ORDER ELFDATA2LSB
- #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- #define HOST_ORDER ELFDATA2MSB
- #endif
- static Elf64_Ehdr *ehdr;
- static Elf64_Shdr *shdr;
- static const char *strtab;
- static bool swap;
- static uint64_t swab_elfxword(uint64_t val)
- {
- return swap ? __builtin_bswap64(val) : val;
- }
- static uint32_t swab_elfword(uint32_t val)
- {
- return swap ? __builtin_bswap32(val) : val;
- }
- static uint16_t swab_elfhword(uint16_t val)
- {
- return swap ? __builtin_bswap16(val) : val;
- }
- int main(int argc, char *argv[])
- {
- struct stat stat;
- int fd, ret;
- if (argc < 3) {
- fprintf(stderr, "file arguments missing\n");
- exit(EXIT_FAILURE);
- }
- fd = open(argv[1], O_RDWR);
- if (fd < 0) {
- fprintf(stderr, "failed to open %s\n", argv[1]);
- exit(EXIT_FAILURE);
- }
- ret = fstat(fd, &stat);
- if (ret < 0) {
- fprintf(stderr, "failed to stat() %s\n", argv[1]);
- exit(EXIT_FAILURE);
- }
- ehdr = mmap(0, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (ehdr == MAP_FAILED) {
- fprintf(stderr, "failed to mmap() %s\n", argv[1]);
- exit(EXIT_FAILURE);
- }
- swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
- shdr = (void *)ehdr + swab_elfxword(ehdr->e_shoff);
- strtab = (void *)ehdr +
- swab_elfxword(shdr[swab_elfhword(ehdr->e_shstrndx)].sh_offset);
- for (int i = 0; i < swab_elfhword(ehdr->e_shnum); i++) {
- unsigned long info, flags;
- bool prel64 = false;
- Elf64_Rela *rela;
- int numrela;
- if (swab_elfword(shdr[i].sh_type) != SHT_RELA)
- continue;
- /* only consider RELA sections operating on data */
- info = swab_elfword(shdr[i].sh_info);
- flags = swab_elfxword(shdr[info].sh_flags);
- if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) != SHF_ALLOC)
- continue;
- /*
- * We generally don't permit ABS64 relocations in the code that
- * runs before relocation processing occurs. If statically
- * initialized absolute symbol references are unavoidable, they
- * may be emitted into a *.rodata.prel64 section and they will
- * be converted to place-relative 64-bit references. This
- * requires special handling in the referring code.
- */
- if (strstr(strtab + swab_elfword(shdr[info].sh_name),
- ".rodata.prel64")) {
- prel64 = true;
- }
- rela = (void *)ehdr + swab_elfxword(shdr[i].sh_offset);
- numrela = swab_elfxword(shdr[i].sh_size) / sizeof(*rela);
- for (int j = 0; j < numrela; j++) {
- uint64_t info = swab_elfxword(rela[j].r_info);
- if (ELF64_R_TYPE(info) != R_AARCH64_ABS64)
- continue;
- if (prel64) {
- /* convert ABS64 into PREL64 */
- info ^= R_AARCH64_ABS64 ^ R_AARCH64_PREL64;
- rela[j].r_info = swab_elfxword(info);
- } else {
- fprintf(stderr,
- "Unexpected absolute relocations detected in %s\n",
- argv[2]);
- close(fd);
- unlink(argv[1]);
- exit(EXIT_FAILURE);
- }
- }
- }
- close(fd);
- return 0;
- }
|