kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

freebsd_note_target.c (5160B)


      1 /* A FreeBSD shared object may leave EI_OSABI at System V and carry its
      2  * platform identity only in an NT_FREEBSD_ABI_TAG note.  Target detection
      3  * must consult that note before the linker performs OS compatibility checks. */
      4 
      5 #include <kit/object.h>
      6 #include <stdint.h>
      7 #include <string.h>
      8 
      9 #include "lib/kit_unit.h"
     10 
     11 enum {
     12   ELF64_EHDR_SIZE = 64,
     13   ELF64_PHDR_SIZE = 56,
     14   ELF64_SHDR_SIZE = 64,
     15   NOTE_SIZE = 24,
     16   NOTE_OFFSET = ELF64_EHDR_SIZE + ELF64_PHDR_SIZE,
     17   SECTION_NOTE_OFFSET = ELF64_EHDR_SIZE + ELF64_SHDR_SIZE,
     18   IMAGE_SIZE = SECTION_NOTE_OFFSET + NOTE_SIZE,
     19 };
     20 
     21 static void put16le(uint8_t* p, uint16_t v) {
     22   p[0] = (uint8_t)v;
     23   p[1] = (uint8_t)(v >> 8);
     24 }
     25 
     26 static void put32le(uint8_t* p, uint32_t v) {
     27   p[0] = (uint8_t)v;
     28   p[1] = (uint8_t)(v >> 8);
     29   p[2] = (uint8_t)(v >> 16);
     30   p[3] = (uint8_t)(v >> 24);
     31 }
     32 
     33 static void put64le(uint8_t* p, uint64_t v) {
     34   put32le(p, (uint32_t)v);
     35   put32le(p + 4, (uint32_t)(v >> 32));
     36 }
     37 
     38 static void make_rv64_elf_with_note(uint8_t image[IMAGE_SIZE],
     39                                     const char owner[8], uint32_t type) {
     40   uint8_t* ph;
     41   uint8_t* note;
     42   memset(image, 0, IMAGE_SIZE);
     43 
     44   image[0] = 0x7f;
     45   image[1] = 'E';
     46   image[2] = 'L';
     47   image[3] = 'F';
     48   image[4] = 2; /* ELFCLASS64 */
     49   image[5] = 1; /* ELFDATA2LSB */
     50   image[6] = 1; /* EV_CURRENT */
     51   image[7] = 0; /* ELFOSABI_NONE / System V */
     52   put16le(image + 16, 3);   /* ET_DYN */
     53   put16le(image + 18, 243); /* EM_RISCV */
     54   put32le(image + 20, 1);   /* EV_CURRENT */
     55   put64le(image + 32, ELF64_EHDR_SIZE);
     56   put16le(image + 52, ELF64_EHDR_SIZE);
     57   put16le(image + 54, ELF64_PHDR_SIZE);
     58   put16le(image + 56, 1);
     59 
     60   ph = image + ELF64_EHDR_SIZE;
     61   put32le(ph, 4); /* PT_NOTE */
     62   put64le(ph + 8, NOTE_OFFSET);
     63   put64le(ph + 32, NOTE_SIZE);
     64   put64le(ph + 40, NOTE_SIZE);
     65   put64le(ph + 48, 4);
     66 
     67   note = image + NOTE_OFFSET;
     68   put32le(note, 8);     /* namesz: "FreeBSD\0" */
     69   put32le(note + 4, 4); /* descsz: ABI version */
     70   put32le(note + 8, type);
     71   memcpy(note + 12, owner, 8);
     72   put32le(note + 20, 1500068);
     73 }
     74 
     75 static void make_rv64_elf_with_section_note(uint8_t image[IMAGE_SIZE],
     76                                             const char owner[8],
     77                                             uint32_t type) {
     78   uint8_t* sh;
     79   uint8_t* note;
     80   make_rv64_elf_with_note(image, owner, type);
     81   put64le(image + 32, 0); /* no program-header table */
     82   put16le(image + 54, 0);
     83   put16le(image + 56, 0);
     84   put64le(image + 40, ELF64_EHDR_SIZE);
     85   put16le(image + 58, ELF64_SHDR_SIZE);
     86   put16le(image + 60, 1);
     87 
     88   sh = image + ELF64_EHDR_SIZE;
     89   memset(sh, 0, ELF64_SHDR_SIZE);
     90   put32le(sh + 4, 7); /* SHT_NOTE */
     91   put64le(sh + 24, SECTION_NOTE_OFFSET);
     92   put64le(sh + 32, NOTE_SIZE);
     93   put64le(sh + 48, 4);
     94 
     95   note = image + SECTION_NOTE_OFFSET;
     96   put32le(note, 8);
     97   put32le(note + 4, 4);
     98   put32le(note + 8, type);
     99   memcpy(note + 12, owner, 8);
    100   put32le(note + 20, 1500068);
    101 }
    102 
    103 int main(void) {
    104   const char freebsd_owner[8] = {'F', 'r', 'e', 'e',
    105                                  'B', 'S', 'D', '\0'};
    106   const char other_owner[8] = {'N', 'o', 't', 'F',
    107                                'r', 'e', 'e', '\0'};
    108   uint8_t image[IMAGE_SIZE];
    109   KitTargetSpec target;
    110   KitUnit u;
    111 
    112   kit_unit_init(&u);
    113 
    114   make_rv64_elf_with_note(image, freebsd_owner, 1);
    115   memset(&target, 0, sizeof target);
    116   CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK,
    117             "SysV-branded FreeBSD ELF is detected");
    118   CU_EXPECT(&u, target.arch == KIT_ARCH_RV64, "RISC-V arch is preserved");
    119   CU_EXPECT(&u, target.obj == KIT_OBJ_ELF, "ELF format is preserved");
    120   CU_EXPECT(&u, target.os == KIT_OS_FREEBSD,
    121             "NT_FREEBSD_ABI_TAG supplies FreeBSD identity");
    122 
    123   make_rv64_elf_with_note(image, other_owner, 1);
    124   memset(&target, 0, sizeof target);
    125   CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK,
    126             "generic SysV ELF is detected");
    127   CU_EXPECT(&u, target.os == KIT_OS_LINUX,
    128             "unrecognized notes do not change the SysV default");
    129 
    130   make_rv64_elf_with_note(image, freebsd_owner, 2);
    131   memset(&target, 0, sizeof target);
    132   CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK,
    133             "ELF with a non-ABI FreeBSD note is detected");
    134   CU_EXPECT(&u, target.os == KIT_OS_LINUX,
    135             "only NT_FREEBSD_ABI_TAG changes target identity");
    136 
    137   make_rv64_elf_with_section_note(image, freebsd_owner, 1);
    138   memset(&target, 0, sizeof target);
    139   CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK,
    140             "section-only FreeBSD ELF is detected");
    141   CU_EXPECT(&u, target.os == KIT_OS_FREEBSD,
    142             "SHT_NOTE FreeBSD ABI tag supplies target identity");
    143 
    144   make_rv64_elf_with_note(image, freebsd_owner, 1);
    145   put32le(image + NOTE_OFFSET, UINT32_MAX);
    146   memset(&target, 0, sizeof target);
    147   CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK,
    148             "malformed note does not invalidate an otherwise detectable ELF");
    149   CU_EXPECT(&u, target.os == KIT_OS_LINUX,
    150             "out-of-bounds note payload is ignored safely");
    151 
    152   kit_unit_summary(&u, "freebsd_note_target");
    153   return kit_unit_status(&u);
    154 }