boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

elf-pvh-note.c (3615B)


      1 /* elf-pvh-note — append a PT_NOTE program header pointing at the
      2  * existing `.note.Xen` section, and retype that section as SHT_NOTE.
      3  *
      4  * Why: tcc 0.9.26's linker emits only PT_LOAD program headers and
      5  * marks every assembler-created section as SHT_PROGBITS, so QEMU's
      6  * PVH `-kernel` path (which scans PT_NOTE phdrs for the Xen 18 note
      7  * to find the 32-bit entry) refuses the kernel with "Error loading
      8  * uncompressed kernel without PVH ELF Note".  Patching the linker is
      9  * a much bigger change than rewriting six fields after the fact;
     10  * tcc reserves the post-Ehdr program-header area only large enough
     11  * for its declared phnum, but the next section content lives at
     12  * 0x200000 (s_align), so writing one extra Phdr at phoff+phnum*phentsize
     13  * fits in the gap.
     14  *
     15  * Usage: elf-pvh-note <elf-path>
     16  */
     17 
     18 extern int   open(const char *, int, ...);
     19 extern long  lseek(int, long, int);
     20 extern long  read(int, void *, unsigned long);
     21 extern long  write(int, const void *, unsigned long);
     22 extern int   close(int);
     23 extern void *malloc(unsigned long);
     24 extern int   strcmp(const char *, const char *);
     25 extern int   printf(const char *, ...);
     26 
     27 #define O_RDWR     2
     28 #define SEEK_SET   0
     29 #define SEEK_END   2
     30 
     31 #define PT_NOTE    4
     32 #define PF_R       4
     33 #define SHT_NOTE   7
     34 
     35 typedef unsigned long  u64;
     36 typedef unsigned int   u32;
     37 typedef unsigned short u16;
     38 typedef unsigned char  u8;
     39 
     40 static u16 r16(u8 *p) { return (u16)p[0] | ((u16)p[1] << 8); }
     41 static u32 r32(u8 *p) {
     42     return (u32)p[0] | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24);
     43 }
     44 static u64 r64(u8 *p) {
     45     return (u64)r32(p) | ((u64)r32(p + 4) << 32);
     46 }
     47 static void w16(u8 *p, u16 v) { p[0] = v; p[1] = v >> 8; }
     48 static void w32(u8 *p, u32 v) {
     49     p[0] = v; p[1] = v >> 8; p[2] = v >> 16; p[3] = v >> 24;
     50 }
     51 static void w64(u8 *p, u64 v) { w32(p, (u32)v); w32(p + 4, (u32)(v >> 32)); }
     52 
     53 int main(int argc, char **argv) {
     54     if (argc != 2) { printf("usage: elf-pvh-note <elf>\n"); return 2; }
     55     int fd = open(argv[1], O_RDWR);
     56     if (fd < 0) { printf("elf-pvh-note: open failed\n"); return 1; }
     57     long size = lseek(fd, 0, SEEK_END);
     58     lseek(fd, 0, SEEK_SET);
     59     u8 *buf = (u8 *)malloc(size);
     60     if (read(fd, buf, size) != size) { printf("elf-pvh-note: short read\n"); return 1; }
     61 
     62     u64 phoff      = r64(buf + 0x20);
     63     u16 phentsize  = r16(buf + 0x36);
     64     u16 phnum      = r16(buf + 0x38);
     65     u64 shoff      = r64(buf + 0x28);
     66     u16 shentsize  = r16(buf + 0x3a);
     67     u16 shnum      = r16(buf + 0x3c);
     68     u16 shstrndx   = r16(buf + 0x3e);
     69 
     70     u64 shstrtab_off = r64(buf + shoff + shstrndx * shentsize + 0x18);
     71 
     72     u64 note_off = 0, note_size = 0, note_addr = 0;
     73     int found = 0;
     74     for (int i = 0; i < shnum; i++) {
     75         u8 *sh = buf + shoff + i * shentsize;
     76         u32 name_off = r32(sh);
     77         if (strcmp((char *)(buf + shstrtab_off + name_off), ".note.Xen") == 0) {
     78             note_addr = r64(sh + 0x10);
     79             note_off  = r64(sh + 0x18);
     80             note_size = r64(sh + 0x20);
     81             w32(sh + 4, SHT_NOTE);
     82             found = 1;
     83             break;
     84         }
     85     }
     86     if (!found) { printf("elf-pvh-note: no .note.Xen section\n"); return 1; }
     87 
     88     u8 *ph = buf + phoff + phnum * phentsize;
     89     w32(ph + 0,  PT_NOTE);
     90     w32(ph + 4,  PF_R);
     91     w64(ph + 8,  note_off);
     92     w64(ph + 16, note_addr);
     93     w64(ph + 24, note_addr);
     94     w64(ph + 32, note_size);
     95     w64(ph + 40, note_size);
     96     w64(ph + 48, 4);
     97     w16(buf + 0x38, phnum + 1);
     98 
     99     lseek(fd, 0, SEEK_SET);
    100     if (write(fd, buf, size) != size) { printf("elf-pvh-note: short write\n"); return 1; }
    101     close(fd);
    102     return 0;
    103 }