1 // zem - makes an ELF file - which we can look at with mez
     
2 
     3 const std = @import("std");
     
4 
     5 const Bytes = struct {
     
6     mem: [0x2000]u8 = undefined,
     
7     pos: usize = 0,
     
8 
     9     pub fn writeNum(self: *Bytes, num: anytype) void {
    
10         const T = @TypeOf(num);
    
11         std.mem.writeIntSliceNative(T, self.mem[self.pos..], num);
    
12 //        std.debug.print("Writing {x} ({s})\n", .{num, @typeName(@TypeOf(num))});
    
13         self.pos += @sizeOf(T);
    
14     }
    
15 
    16     pub fn writeBytes(self: *Bytes, source_bytes: []const u8) void {
    
17 //        std.debug.print("Writing {d} bytes\n", .{source_bytes.len});
    
18         for (source_bytes) |b| {
    
19 //            std.debug.print("  0x{x}: {x}\n", .{self.pos, b});
    
20             self.mem[self.pos] = b;
    
21             self.pos += 1;
    
22         }
    
23     }
    
24 
    25     pub fn padTo(self: *Bytes, addr: usize) void {
    
26         while (self.pos < addr) {
    
27             self.mem[self.pos] = 0;
    
28             self.pos += 1;
    
29         }
    
30     }
    
31 
    32     pub fn print(self: Bytes) void {
    
33         for(self.mem[0..self.pos], 0..self.pos) |b,a| {
    
34             std.debug.print("\x1b[90m{x}:\x1b[39m{x} ", .{a,b});
    
35         }
    
36         std.debug.print("\n", .{});
    
37     }
    
38 
    39     pub fn get(self: Bytes) []const u8 {
    
40         return self.mem[0..self.pos];
    
41     }
    
42 };
    
43 
    44 pub fn main() !void {
    
45 //    var bytes: [100]u8 = undefined;
    
46 //    var pos: usize = 0;
    
47 
    48     var bytes = Bytes{};
    
49 
    50     // hard-coding for ease!
    
51     const segment_count = 2;
    
52     const program_mem_addr: u32 = 0x8040000;
    
53     const data_mem_addr: u32 = 0x8041000;
    
54     const ph_size = 32; // program header size (bytes)
    
55     const elf_size = 52; // main elf header size (bytes)
    
56     const total_header = elf_size + (ph_size * segment_count);
    
57     const entry_addr = program_mem_addr + total_header;
    
58 
    59 std.debug.print("total header: {d} bytes\n", .{total_header});
    
60 
    61     bytes.writeBytes(&[_]u8{ 0x7F, 'E', 'L', 'F' }); // magic
    
62     bytes.writeNum(@as(u8, 1)); // 32-bit            0x04
    
63     bytes.writeNum(@as(u8, 1)); // little endian     0x05
    
64     bytes.writeNum(@as(u8, 1)); // elf version       0x06
    
65     bytes.writeNum(@as(u8, 0)); // systemV os abi    0x07
    
66     bytes.writeNum(@as(u8, 0)); // abi version       0x08
    
67     bytes.writeBytes(&[_]u8{
    
68         0, // pad 0x09
    
69         0, // pad 0x0a
    
70         0, // pad 0x0b
    
71         0, // pad 0x0c      (7 bytes padding)
    
72         0, // pad 0x0d
    
73         0, // pad 0x0e
    
74         0, // pad 0x0f
    
75     });
    
76     bytes.writeNum(@as(u16, 2)); // executable        0x10
    
77     bytes.writeNum(@as(u16, 3)); // arch intel 80386  0x12
    
78     bytes.writeNum(@as(u32, 1)); // ELF version       0x14
    
79     bytes.writeNum(entry_addr); // entry address!     0x18
    
80 
    81     // next is elf_size because program headers start right after
    
82     // main elf header.
    
83     bytes.writeNum(@as(u32, elf_size)); // e_phoff    0x1C
    
84 
    85     // Stuff
    
86     bytes.writeNum(@as(u32, 0)); // e_shoff ignore!   0x20
    
87     bytes.writeNum(@as(u32, 0)); // e_flags           0x24
    
88     bytes.writeNum(@as(u16, elf_size)); // e_hsize    0x28
    
89 
    90     // Program header size and count
    
91     bytes.writeNum(@as(u16, 32)); // ph size (each)   0x2A
    
92     bytes.writeNum(@as(u16, 2)); // ph count          0x2C
    
93 
    94     // More section stuff to ignore:
    
95     bytes.writeNum(@as(u16, 0)); // sh size           0x2E
    
96     bytes.writeNum(@as(u16, 0)); // sh count          0x30
    
97     bytes.writeNum(@as(u16, 0)); // sh str idx        0x32
    
98 
    99     // Program Header 1
   
100     // ================================================
   
101     bytes.writeNum(@as(u32, 1)); // ptype (1=LOAD)
   
102     bytes.writeNum(@as(u32, 0)); // file offset to load!
   
103     bytes.writeNum(@as(u32, program_mem_addr)); // write to mem!
   
104     bytes.writeNum(@as(u32, program_mem_addr)); // same (physical)
   
105     bytes.writeNum(@as(u32, 0x1000)); // bytes to write
   
106     bytes.writeNum(@as(u32, 0x1000)); // memory to alloc
   
107     bytes.writeNum(@as(u32, 5)); // flags (RX)
   
108     bytes.writeNum(@as(u32, 0x1000)); // alignment
   
109 
   110     // Program Header 2
   
111     // ================================================
   
112     bytes.writeNum(@as(u32, 1)); // ptype (1=LOAD)
   
113     bytes.writeNum(@as(u32, 0x1000)); // file offset to load!
   
114     bytes.writeNum(@as(u32, data_mem_addr)); // write to mem!
   
115     bytes.writeNum(@as(u32, data_mem_addr)); // same (physical)
   
116     bytes.writeNum(@as(u32, 13)); // bytes to write
   
117     bytes.writeNum(@as(u32, 13)); // memory to alloc
   
118     bytes.writeNum(@as(u32, 6)); // flags (RW)
   
119     bytes.writeNum(@as(u32, 0x1000)); // alignment
   
120 
   121     // Write program (0x22 bytes)
   
122     // ================================================
   
123     bytes.writeBytes(&[_]u8{
   
124         // comes from hello.asm - then hand-edited address to
   
125         // point to my data segment: 0x8041000
   
126         0xba, 0x0d, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x10, 0x04, 0x08,
   
127         0xbb, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x00, 0x00,
   
128         0xcd, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00,
   
129         0x00, 0x00, 0xcd, 0x80,
   
130     });
   
131 
   132     // Pad to next 0x1000, then write string data
   
133     // ================================================
   
134     bytes.padTo(0x1000);
   
135     bytes.writeBytes("Hello world.\x0a");
   
136 
   137 
   138     // Print what we're gonna write to compare with mez
   
139     // LOL - not now that there's 1kb padding!
   
140     //bytes.print();
   
141 
   142     const file = try std.fs.cwd().createFile("foo", .{
   
143         .mode = 0o777,
   
144     });
   
145     defer file.close();
   
146     _ = try file.write(bytes.get());
   
147 }