authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 23:04:43+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 23:04:43+01:00
log720dd80007bf2bee0bb69f2c7ecd37c6af9adb17
treea59fd6fd43039eccfd2ffb6f3862ee6688d1ce5e
parentca6f41ee30a53232dd951d2b00af73f1e8b5e698

elf+riscv: implement enough to get basic hello world in C working


2 files changed, 224 insertions(+), 1 deletions(-)

src/link/Elf/Atom.zig+212-1
...@@ -442,6 +442,10 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype...@@ -442,6 +442,10 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
442 error.RelocFailure => has_reloc_errors = true,442 error.RelocFailure => has_reloc_errors = true,
443 else => |e| return e,443 else => |e| return e,
444 },444 },
445 .riscv64 => riscv.scanReloc(self, elf_file, rel, symbol, code, &it) catch |err| switch (err) {
446 error.RelocFailure => has_reloc_errors = true,
447 else => |e| return e,
448 },
445 else => return error.UnsupportedCpuArch,449 else => return error.UnsupportedCpuArch,
446 }450 }
447 }451 }
...@@ -776,6 +780,12 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -776,6 +780,12 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
776 => has_reloc_errors = true,780 => has_reloc_errors = true,
777 else => |e| return e,781 else => |e| return e,
778 },782 },
783 .riscv64 => riscv.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
784 error.RelocFailure,
785 error.RelaxFailure,
786 => has_reloc_errors = true,
787 else => |e| return e,
788 },
779 else => return error.UnsupportedCpuArch,789 else => return error.UnsupportedCpuArch,
780 }790 }
781 }791 }
...@@ -953,6 +963,10 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -953,6 +963,10 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
953 error.RelocFailure => has_reloc_errors = true,963 error.RelocFailure => has_reloc_errors = true,
954 else => |e| return e,964 else => |e| return e,
955 },965 },
966 .riscv64 => riscv.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
967 error.RelocFailure => has_reloc_errors = true,
968 else => |e| return e,
969 },
956 else => return error.UnsupportedCpuArch,970 else => return error.UnsupportedCpuArch,
957 }971 }
958 }972 }
...@@ -1756,6 +1770,202 @@ const aarch64 = struct {...@@ -1756,6 +1770,202 @@ const aarch64 = struct {
1756 const aarch64_util = @import("../aarch64.zig");1770 const aarch64_util = @import("../aarch64.zig");
1757};1771};
17581772
1773const riscv = struct {
1774 fn scanReloc(
1775 atom: Atom,
1776 elf_file: *Elf,
1777 rel: elf.Elf64_Rela,
1778 symbol: *Symbol,
1779 code: ?[]const u8,
1780 it: *RelocsIterator,
1781 ) !void {
1782 _ = code;
1783 _ = it;
1784
1785 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
1786
1787 switch (r_type) {
1788 .@"64" => {
1789 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
1790 },
1791
1792 .HI20 => {
1793 try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file);
1794 },
1795
1796 .CALL_PLT => if (symbol.flags.import) {
1797 symbol.flags.needs_plt = true;
1798 },
1799
1800 .GOT_HI20 => {
1801 symbol.flags.needs_got = true;
1802 },
1803
1804 .PCREL_HI20,
1805 .PCREL_LO12_I,
1806 .PCREL_LO12_S,
1807 .LO12_I,
1808 .ADD32,
1809 .SUB32,
1810 => {},
1811
1812 else => try atom.reportUnhandledRelocError(rel, elf_file),
1813 }
1814 }
1815
1816 fn resolveRelocAlloc(
1817 atom: Atom,
1818 elf_file: *Elf,
1819 rel: elf.Elf64_Rela,
1820 target: *const Symbol,
1821 args: ResolveArgs,
1822 it: *RelocsIterator,
1823 code: []u8,
1824 stream: anytype,
1825 ) !void {
1826 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
1827 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
1828 const cwriter = stream.writer();
1829
1830 const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;
1831 _ = TP;
1832 _ = DTP;
1833 _ = ZIG_GOT;
1834
1835 switch (r_type) {
1836 .NONE => unreachable,
1837
1838 .@"64" => {
1839 try atom.resolveDynAbsReloc(
1840 target,
1841 rel,
1842 dynAbsRelocAction(target, elf_file),
1843 elf_file,
1844 cwriter,
1845 );
1846 },
1847
1848 .ADD32 => riscv_util.writeAddend(i32, .add, code[r_offset..][0..4], S + A),
1849 .SUB32 => riscv_util.writeAddend(i32, .sub, code[r_offset..][0..4], S + A),
1850
1851 .HI20 => {
1852 const value: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow);
1853 riscv_util.writeInstU(code[r_offset..][0..4], value);
1854 },
1855
1856 .LO12_I => {
1857 const value: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow);
1858 riscv_util.writeInstI(code[r_offset..][0..4], value);
1859 },
1860
1861 .GOT_HI20 => {
1862 assert(target.flags.has_got);
1863 const disp: u32 = @bitCast(math.cast(i32, G + GOT + A - P) orelse return error.Overflow);
1864 riscv_util.writeInstU(code[r_offset..][0..4], disp);
1865 },
1866
1867 .CALL_PLT => {
1868 // TODO: relax
1869 const disp: u32 = @bitCast(math.cast(i32, S + A - P) orelse return error.Overflow);
1870 riscv_util.writeInstU(code[r_offset..][0..4], disp); // auipc
1871 riscv_util.writeInstI(code[r_offset + 4 ..][0..4], disp); // jalr
1872 },
1873
1874 .PCREL_HI20 => {
1875 const disp: u32 = @bitCast(math.cast(i32, S + A - P) orelse return error.Overflow);
1876 riscv_util.writeInstU(code[r_offset..][0..4], disp);
1877 },
1878
1879 .PCREL_LO12_I,
1880 .PCREL_LO12_S,
1881 => {
1882 assert(A == 0); // according to the spec
1883 // We need to find the paired reloc for this relocation.
1884 // TODO: should we search forward too?
1885 const file_ptr = atom.file(elf_file).?;
1886 const pos = it.pos;
1887 const pair = while (it.prev()) |pair| {
1888 if (target.address(.{}, elf_file) == atom.address(elf_file) + pair.r_offset) {
1889 break pair;
1890 }
1891 } else unreachable; // TODO error
1892 it.pos = pos;
1893 const target_ = switch (file_ptr) {
1894 .zig_object => |x| elf_file.symbol(x.symbol(pair.r_sym())),
1895 .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]),
1896 else => unreachable,
1897 };
1898 const S_ = @as(i64, @intCast(target_.address(.{}, elf_file)));
1899 const A_ = pair.r_addend;
1900 const P_ = @as(i64, @intCast(atom.address(elf_file) + pair.r_offset));
1901 const G_ = @as(i64, @intCast(target_.gotAddress(elf_file))) - GOT;
1902 const disp = switch (@as(elf.R_RISCV, @enumFromInt(pair.r_type()))) {
1903 .PCREL_HI20 => math.cast(i32, S_ + A_ - P_) orelse return error.Overflow,
1904 .GOT_HI20 => math.cast(i32, G_ + GOT + A_ - P_) orelse return error.Overflow,
1905 else => unreachable,
1906 };
1907 relocs_log.debug(" [{x} => {x}]", .{ P_, disp + P_ });
1908 switch (r_type) {
1909 .PCREL_LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], @bitCast(disp)),
1910 .PCREL_LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], @bitCast(disp)),
1911 else => unreachable,
1912 }
1913 },
1914
1915 else => try atom.reportUnhandledRelocError(rel, elf_file),
1916 }
1917 }
1918
1919 fn resolveRelocNonAlloc(
1920 atom: Atom,
1921 elf_file: *Elf,
1922 rel: elf.Elf64_Rela,
1923 target: *const Symbol,
1924 args: ResolveArgs,
1925 it: *RelocsIterator,
1926 code: []u8,
1927 stream: anytype,
1928 ) !void {
1929 _ = target;
1930 _ = it;
1931
1932 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
1933 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
1934 const cwriter = stream.writer();
1935
1936 _, const A, const S, const GOT, _, _, const DTP, _ = args;
1937 _ = GOT;
1938 _ = DTP;
1939
1940 switch (r_type) {
1941 .NONE => unreachable,
1942
1943 .@"32" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
1944 .@"64" => try cwriter.writeInt(i64, S + A, .little),
1945
1946 .ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A),
1947 .SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A),
1948 .ADD16 => riscv_util.writeAddend(i16, .add, code[r_offset..][0..2], S + A),
1949 .SUB16 => riscv_util.writeAddend(i16, .sub, code[r_offset..][0..2], S + A),
1950 .ADD32 => riscv_util.writeAddend(i32, .add, code[r_offset..][0..4], S + A),
1951 .SUB32 => riscv_util.writeAddend(i32, .sub, code[r_offset..][0..4], S + A),
1952 .ADD64 => riscv_util.writeAddend(i64, .add, code[r_offset..][0..8], S + A),
1953 .SUB64 => riscv_util.writeAddend(i64, .sub, code[r_offset..][0..8], S + A),
1954
1955 .SET8 => mem.writeInt(i8, code[r_offset..][0..1], @as(i8, @truncate(S + A)), .little),
1956 .SET16 => mem.writeInt(i16, code[r_offset..][0..2], @as(i16, @truncate(S + A)), .little),
1957 .SET32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A)), .little),
1958
1959 .SET6 => riscv_util.writeSetSub6(.set, code[r_offset..][0..1], S + A),
1960 .SUB6 => riscv_util.writeSetSub6(.sub, code[r_offset..][0..1], S + A),
1961
1962 else => try atom.reportUnhandledRelocError(rel, elf_file),
1963 }
1964 }
1965
1966 const riscv_util = @import("../riscv.zig");
1967};
1968
1759const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 };1969const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 };
17601970
1761const RelocError = error{1971const RelocError = error{
...@@ -1796,10 +2006,11 @@ const elf = std.elf;...@@ -1796,10 +2006,11 @@ const elf = std.elf;
1796const eh_frame = @import("eh_frame.zig");2006const eh_frame = @import("eh_frame.zig");
1797const log = std.log.scoped(.link);2007const log = std.log.scoped(.link);
1798const math = std.math;2008const math = std.math;
2009const mem = std.mem;
1799const relocs_log = std.log.scoped(.link_relocs);2010const relocs_log = std.log.scoped(.link_relocs);
1800const relocation = @import("relocation.zig");2011const relocation = @import("relocation.zig");
18012012
1802const Allocator = std.mem.Allocator;2013const Allocator = mem.Allocator;
1803const Atom = @This();2014const Atom = @This();
1804const Elf = @import("../Elf.zig");2015const Elf = @import("../Elf.zig");
1805const Fde = eh_frame.Fde;2016const Fde = eh_frame.Fde;
src/link/Elf/eh_frame.zig+12
...@@ -319,6 +319,7 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file:...@@ -319,6 +319,7 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file:
319 switch (cpu_arch) {319 switch (cpu_arch) {
320 .x86_64 => try x86_64.resolveReloc(rec, elf_file, rel, P, S + A, contents[offset..]),320 .x86_64 => try x86_64.resolveReloc(rec, elf_file, rel, P, S + A, contents[offset..]),
321 .aarch64 => try aarch64.resolveReloc(rec, elf_file, rel, P, S + A, contents[offset..]),321 .aarch64 => try aarch64.resolveReloc(rec, elf_file, rel, P, S + A, contents[offset..]),
322 .riscv64 => try riscv.resolveReloc(rec, elf_file, rel, P, S + A, contents[offset..]),
322 else => return error.UnsupportedCpuArch,323 else => return error.UnsupportedCpuArch,
323 }324 }
324}325}
...@@ -577,6 +578,17 @@ const aarch64 = struct {...@@ -577,6 +578,17 @@ const aarch64 = struct {
577 }578 }
578};579};
579580
581const riscv = struct {
582 fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void {
583 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
584 switch (r_type) {
585 .NONE => {},
586 .@"32_PCREL" => std.mem.writeInt(i32, data[0..4], @as(i32, @intCast(target - source)), .little),
587 else => try reportInvalidReloc(rec, elf_file, rel),
588 }
589 }
590};
591
580fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {592fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {
581 var err = try elf_file.addErrorWithNotes(1);593 var err = try elf_file.addErrorWithNotes(1);
582 try err.addMsg(elf_file, "invalid relocation type {} at offset 0x{x}", .{594 try err.addMsg(elf_file, "invalid relocation type {} at offset 0x{x}", .{