18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * arch/alpha/boot/tools/objstrip.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Strip the object file headers/trailers from an executable (ELF or ECOFF).
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 1996 David Mosberger-Tang.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci/*
108c2ecf20Sopenharmony_ci * Converts an ECOFF or ELF object file into a bootable file.  The
118c2ecf20Sopenharmony_ci * object file must be a OMAGIC file (i.e., data and bss follow immediately
128c2ecf20Sopenharmony_ci * behind the text).  See DEC "Assembly Language Programmer's Guide"
138c2ecf20Sopenharmony_ci * documentation for details.  The SRM boot process is documented in
148c2ecf20Sopenharmony_ci * the Alpha AXP Architecture Reference Manual, Second Edition by
158c2ecf20Sopenharmony_ci * Richard L. Sites and Richard T. Witek.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci#include <stdio.h>
188c2ecf20Sopenharmony_ci#include <string.h>
198c2ecf20Sopenharmony_ci#include <stdlib.h>
208c2ecf20Sopenharmony_ci#include <unistd.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <sys/fcntl.h>
238c2ecf20Sopenharmony_ci#include <sys/stat.h>
248c2ecf20Sopenharmony_ci#include <sys/types.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/a.out.h>
278c2ecf20Sopenharmony_ci#include <linux/coff.h>
288c2ecf20Sopenharmony_ci#include <linux/param.h>
298c2ecf20Sopenharmony_ci#ifdef __ELF__
308c2ecf20Sopenharmony_ci# include <linux/elf.h>
318c2ecf20Sopenharmony_ci# define elfhdr elf64_hdr
328c2ecf20Sopenharmony_ci# define elf_phdr elf64_phdr
338c2ecf20Sopenharmony_ci# define elf_check_arch(x) ((x)->e_machine == EM_ALPHA)
348c2ecf20Sopenharmony_ci#endif
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* bootfile size must be multiple of BLOCK_SIZE: */
378c2ecf20Sopenharmony_ci#define BLOCK_SIZE	512
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciconst char * prog_name;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic void
438c2ecf20Sopenharmony_ciusage (void)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci    fprintf(stderr,
468c2ecf20Sopenharmony_ci	    "usage: %s [-v] -p file primary\n"
478c2ecf20Sopenharmony_ci	    "       %s [-vb] file [secondary]\n", prog_name, prog_name);
488c2ecf20Sopenharmony_ci    exit(1);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciint
538c2ecf20Sopenharmony_cimain (int argc, char *argv[])
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci    size_t nwritten, tocopy, n, mem_size, fil_size, pad = 0;
568c2ecf20Sopenharmony_ci    int fd, ofd, i, j, verbose = 0, primary = 0;
578c2ecf20Sopenharmony_ci    char buf[8192], *inname;
588c2ecf20Sopenharmony_ci    struct exec * aout;		/* includes file & aout header */
598c2ecf20Sopenharmony_ci    long offset;
608c2ecf20Sopenharmony_ci#ifdef __ELF__
618c2ecf20Sopenharmony_ci    struct elfhdr *elf;
628c2ecf20Sopenharmony_ci    struct elf_phdr *elf_phdr;	/* program header */
638c2ecf20Sopenharmony_ci    unsigned long long e_entry;
648c2ecf20Sopenharmony_ci#endif
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci    prog_name = argv[0];
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci    for (i = 1; i < argc && argv[i][0] == '-'; ++i) {
698c2ecf20Sopenharmony_ci	for (j = 1; argv[i][j]; ++j) {
708c2ecf20Sopenharmony_ci	    switch (argv[i][j]) {
718c2ecf20Sopenharmony_ci	      case 'v':
728c2ecf20Sopenharmony_ci		  verbose = ~verbose;
738c2ecf20Sopenharmony_ci		  break;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	      case 'b':
768c2ecf20Sopenharmony_ci		  pad = BLOCK_SIZE;
778c2ecf20Sopenharmony_ci		  break;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	      case 'p':
808c2ecf20Sopenharmony_ci		  primary = 1;		/* make primary bootblock */
818c2ecf20Sopenharmony_ci		  break;
828c2ecf20Sopenharmony_ci	    }
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci    }
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci    if (i >= argc) {
878c2ecf20Sopenharmony_ci	usage();
888c2ecf20Sopenharmony_ci    }
898c2ecf20Sopenharmony_ci    inname = argv[i++];
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci    fd = open(inname, O_RDONLY);
928c2ecf20Sopenharmony_ci    if (fd == -1) {
938c2ecf20Sopenharmony_ci	perror("open");
948c2ecf20Sopenharmony_ci	exit(1);
958c2ecf20Sopenharmony_ci    }
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci    ofd = 1;
988c2ecf20Sopenharmony_ci    if (i < argc) {
998c2ecf20Sopenharmony_ci	ofd = open(argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0666);
1008c2ecf20Sopenharmony_ci	if (ofd == -1) {
1018c2ecf20Sopenharmony_ci	    perror("open");
1028c2ecf20Sopenharmony_ci	    exit(1);
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci    }
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci    if (primary) {
1078c2ecf20Sopenharmony_ci	/* generate bootblock for primary loader */
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	unsigned long bb[64], sum = 0;
1108c2ecf20Sopenharmony_ci	struct stat st;
1118c2ecf20Sopenharmony_ci	off_t size;
1128c2ecf20Sopenharmony_ci	int i;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (ofd == 1) {
1158c2ecf20Sopenharmony_ci	    usage();
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (fstat(fd, &st) == -1) {
1198c2ecf20Sopenharmony_ci	    perror("fstat");
1208c2ecf20Sopenharmony_ci	    exit(1);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	size = (st.st_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);
1248c2ecf20Sopenharmony_ci	memset(bb, 0, sizeof(bb));
1258c2ecf20Sopenharmony_ci	strcpy((char *) bb, "Linux SRM bootblock");
1268c2ecf20Sopenharmony_ci	bb[60] = size / BLOCK_SIZE;	/* count */
1278c2ecf20Sopenharmony_ci	bb[61] = 1;			/* starting sector # */
1288c2ecf20Sopenharmony_ci	bb[62] = 0;			/* flags---must be 0 */
1298c2ecf20Sopenharmony_ci	for (i = 0; i < 63; ++i) {
1308c2ecf20Sopenharmony_ci	    sum += bb[i];
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci	bb[63] = sum;
1338c2ecf20Sopenharmony_ci	if (write(ofd, bb, sizeof(bb)) != sizeof(bb)) {
1348c2ecf20Sopenharmony_ci	    perror("boot-block write");
1358c2ecf20Sopenharmony_ci	    exit(1);
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	printf("%lu\n", size);
1388c2ecf20Sopenharmony_ci	return 0;
1398c2ecf20Sopenharmony_ci    }
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci    /* read and inspect exec header: */
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci    if (read(fd, buf, sizeof(buf)) < 0) {
1448c2ecf20Sopenharmony_ci	perror("read");
1458c2ecf20Sopenharmony_ci	exit(1);
1468c2ecf20Sopenharmony_ci    }
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#ifdef __ELF__
1498c2ecf20Sopenharmony_ci    elf = (struct elfhdr *) buf;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci    if (memcmp(&elf->e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
1528c2ecf20Sopenharmony_ci	if (elf->e_type != ET_EXEC) {
1538c2ecf20Sopenharmony_ci	    fprintf(stderr, "%s: %s is not an ELF executable\n",
1548c2ecf20Sopenharmony_ci		    prog_name, inname);
1558c2ecf20Sopenharmony_ci	    exit(1);
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci	if (!elf_check_arch(elf)) {
1588c2ecf20Sopenharmony_ci	    fprintf(stderr, "%s: is not for this processor (e_machine=%d)\n",
1598c2ecf20Sopenharmony_ci		    prog_name, elf->e_machine);
1608c2ecf20Sopenharmony_ci	    exit(1);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci	if (elf->e_phnum != 1) {
1638c2ecf20Sopenharmony_ci	    fprintf(stderr,
1648c2ecf20Sopenharmony_ci		    "%s: %d program headers (forgot to link with -N?)\n",
1658c2ecf20Sopenharmony_ci		    prog_name, elf->e_phnum);
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	e_entry = elf->e_entry;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	lseek(fd, elf->e_phoff, SEEK_SET);
1718c2ecf20Sopenharmony_ci	if (read(fd, buf, sizeof(*elf_phdr)) != sizeof(*elf_phdr)) {
1728c2ecf20Sopenharmony_ci	    perror("read");
1738c2ecf20Sopenharmony_ci	    exit(1);
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	elf_phdr = (struct elf_phdr *) buf;
1778c2ecf20Sopenharmony_ci	offset	 = elf_phdr->p_offset;
1788c2ecf20Sopenharmony_ci	mem_size = elf_phdr->p_memsz;
1798c2ecf20Sopenharmony_ci	fil_size = elf_phdr->p_filesz;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* work around ELF bug: */
1828c2ecf20Sopenharmony_ci	if (elf_phdr->p_vaddr < e_entry) {
1838c2ecf20Sopenharmony_ci	    unsigned long delta = e_entry - elf_phdr->p_vaddr;
1848c2ecf20Sopenharmony_ci	    offset   += delta;
1858c2ecf20Sopenharmony_ci	    mem_size -= delta;
1868c2ecf20Sopenharmony_ci	    fil_size -= delta;
1878c2ecf20Sopenharmony_ci	    elf_phdr->p_vaddr += delta;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (verbose) {
1918c2ecf20Sopenharmony_ci	    fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
1928c2ecf20Sopenharmony_ci		    prog_name, (long) elf_phdr->p_vaddr,
1938c2ecf20Sopenharmony_ci		    elf_phdr->p_vaddr + fil_size, offset);
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci    } else
1968c2ecf20Sopenharmony_ci#endif
1978c2ecf20Sopenharmony_ci    {
1988c2ecf20Sopenharmony_ci	aout = (struct exec *) buf;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (!(aout->fh.f_flags & COFF_F_EXEC)) {
2018c2ecf20Sopenharmony_ci	    fprintf(stderr, "%s: %s is not in executable format\n",
2028c2ecf20Sopenharmony_ci		    prog_name, inname);
2038c2ecf20Sopenharmony_ci	    exit(1);
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (aout->fh.f_opthdr != sizeof(aout->ah)) {
2078c2ecf20Sopenharmony_ci	    fprintf(stderr, "%s: %s has unexpected optional header size\n",
2088c2ecf20Sopenharmony_ci		    prog_name, inname);
2098c2ecf20Sopenharmony_ci	    exit(1);
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (N_MAGIC(*aout) != OMAGIC) {
2138c2ecf20Sopenharmony_ci	    fprintf(stderr, "%s: %s is not an OMAGIC file\n",
2148c2ecf20Sopenharmony_ci		    prog_name, inname);
2158c2ecf20Sopenharmony_ci	    exit(1);
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	offset = N_TXTOFF(*aout);
2188c2ecf20Sopenharmony_ci	fil_size = aout->ah.tsize + aout->ah.dsize;
2198c2ecf20Sopenharmony_ci	mem_size = fil_size + aout->ah.bsize;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (verbose) {
2228c2ecf20Sopenharmony_ci	    fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
2238c2ecf20Sopenharmony_ci		    prog_name, aout->ah.text_start,
2248c2ecf20Sopenharmony_ci		    aout->ah.text_start + fil_size, offset);
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci    }
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci    if (lseek(fd, offset, SEEK_SET) != offset) {
2298c2ecf20Sopenharmony_ci	perror("lseek");
2308c2ecf20Sopenharmony_ci	exit(1);
2318c2ecf20Sopenharmony_ci    }
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci    if (verbose) {
2348c2ecf20Sopenharmony_ci	fprintf(stderr, "%s: copying %lu byte from %s\n",
2358c2ecf20Sopenharmony_ci		prog_name, (unsigned long) fil_size, inname);
2368c2ecf20Sopenharmony_ci    }
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci    tocopy = fil_size;
2398c2ecf20Sopenharmony_ci    while (tocopy > 0) {
2408c2ecf20Sopenharmony_ci	n = tocopy;
2418c2ecf20Sopenharmony_ci	if (n > sizeof(buf)) {
2428c2ecf20Sopenharmony_ci	    n = sizeof(buf);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci	tocopy -= n;
2458c2ecf20Sopenharmony_ci	if ((size_t) read(fd, buf, n) != n) {
2468c2ecf20Sopenharmony_ci	    perror("read");
2478c2ecf20Sopenharmony_ci	    exit(1);
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci	do {
2508c2ecf20Sopenharmony_ci	    nwritten = write(ofd, buf, n);
2518c2ecf20Sopenharmony_ci	    if ((ssize_t) nwritten == -1) {
2528c2ecf20Sopenharmony_ci		perror("write");
2538c2ecf20Sopenharmony_ci		exit(1);
2548c2ecf20Sopenharmony_ci	    }
2558c2ecf20Sopenharmony_ci	    n -= nwritten;
2568c2ecf20Sopenharmony_ci	} while (n > 0);
2578c2ecf20Sopenharmony_ci    }
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci    if (pad) {
2608c2ecf20Sopenharmony_ci	mem_size = ((mem_size + pad - 1) / pad) * pad;
2618c2ecf20Sopenharmony_ci    }
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci    tocopy = mem_size - fil_size;
2648c2ecf20Sopenharmony_ci    if (tocopy > 0) {
2658c2ecf20Sopenharmony_ci	fprintf(stderr,
2668c2ecf20Sopenharmony_ci		"%s: zero-filling bss and aligning to %lu with %lu bytes\n",
2678c2ecf20Sopenharmony_ci		prog_name, pad, (unsigned long) tocopy);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	memset(buf, 0x00, sizeof(buf));
2708c2ecf20Sopenharmony_ci	do {
2718c2ecf20Sopenharmony_ci	    n = tocopy;
2728c2ecf20Sopenharmony_ci	    if (n > sizeof(buf)) {
2738c2ecf20Sopenharmony_ci		n = sizeof(buf);
2748c2ecf20Sopenharmony_ci	    }
2758c2ecf20Sopenharmony_ci	    nwritten = write(ofd, buf, n);
2768c2ecf20Sopenharmony_ci	    if ((ssize_t) nwritten == -1) {
2778c2ecf20Sopenharmony_ci		perror("write");
2788c2ecf20Sopenharmony_ci		exit(1);
2798c2ecf20Sopenharmony_ci	    }
2808c2ecf20Sopenharmony_ci	    tocopy -= nwritten;
2818c2ecf20Sopenharmony_ci	} while (tocopy > 0);
2828c2ecf20Sopenharmony_ci    }
2838c2ecf20Sopenharmony_ci    return 0;
2848c2ecf20Sopenharmony_ci}
285