| ... | @@ -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 | }; |
| 1758 | | 1772 | |
| | 1773 | const 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 | |
| 1759 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 }; | 1969 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 }; |
| 1760 | | 1970 | |
| 1761 | const RelocError = error{ | 1971 | const RelocError = error{ |
| ... | @@ -1796,10 +2006,11 @@ const elf = std.elf; | ... | @@ -1796,10 +2006,11 @@ const elf = std.elf; |
| 1796 | const eh_frame = @import("eh_frame.zig"); | 2006 | const eh_frame = @import("eh_frame.zig"); |
| 1797 | const log = std.log.scoped(.link); | 2007 | const log = std.log.scoped(.link); |
| 1798 | const math = std.math; | 2008 | const math = std.math; |
| | 2009 | const mem = std.mem; |
| 1799 | const relocs_log = std.log.scoped(.link_relocs); | 2010 | const relocs_log = std.log.scoped(.link_relocs); |
| 1800 | const relocation = @import("relocation.zig"); | 2011 | const relocation = @import("relocation.zig"); |
| 1801 | | 2012 | |
| 1802 | const Allocator = std.mem.Allocator; | 2013 | const Allocator = mem.Allocator; |
| 1803 | const Atom = @This(); | 2014 | const Atom = @This(); |
| 1804 | const Elf = @import("../Elf.zig"); | 2015 | const Elf = @import("../Elf.zig"); |
| 1805 | const Fde = eh_frame.Fde; | 2016 | const Fde = eh_frame.Fde; |