| ... | ... | @@ -442,6 +442,10 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype |
| 442 | 442 | error.RelocFailure => has_reloc_errors = true, |
| 443 | 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 | 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 | 780 | => has_reloc_errors = true, |
| 777 | 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 | 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 | 963 | error.RelocFailure => has_reloc_errors = true, |
| 954 | 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 | 970 | else => return error.UnsupportedCpuArch, |
| 957 | 971 | } |
| 958 | 972 | } |
| ... | ... | @@ -1756,6 +1770,202 @@ const aarch64 = struct { |
| 1756 | 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 | 1969 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 }; |
| 1760 | 1970 | |
| 1761 | 1971 | const RelocError = error{ |
| ... | ... | @@ -1796,10 +2006,11 @@ const elf = std.elf; |
| 1796 | 2006 | const eh_frame = @import("eh_frame.zig"); |
| 1797 | 2007 | const log = std.log.scoped(.link); |
| 1798 | 2008 | const math = std.math; |
| 2009 | const mem = std.mem; |
| 1799 | 2010 | const relocs_log = std.log.scoped(.link_relocs); |
| 1800 | 2011 | const relocation = @import("relocation.zig"); |
| 1801 | 2012 | |
| 1802 | | const Allocator = std.mem.Allocator; |
| 2013 | const Allocator = mem.Allocator; |
| 1803 | 2014 | const Atom = @This(); |
| 1804 | 2015 | const Elf = @import("../Elf.zig"); |
| 1805 | 2016 | const Fde = eh_frame.Fde; |