authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2025-11-29 19:16:11-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-01 19:17:52-08:00
log85053a6a36ac1d76ab226943ddecb849e21ef4c6
treefdb14a83e3de7083d5342ca7ddd5b9d7a6abe0e7
parentc4f5dda135616207c24a6009e221724f5a6fa6aa

link.Elf: implement aarch64 relocation


2 files changed, 13 insertions(+), 32 deletions(-)

src/link/Elf/Atom.zig+7-32
...@@ -1499,22 +1499,18 @@ const aarch64 = struct {...@@ -1499,22 +1499,18 @@ const aarch64 = struct {
1499 .ABS64 => {1499 .ABS64 => {
1500 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);1500 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
1501 },1501 },
1502
1503 .ADR_PREL_PG_HI21 => {1502 .ADR_PREL_PG_HI21 => {
1504 try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);1503 try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);
1505 },1504 },
1506
1507 .ADR_GOT_PAGE => {1505 .ADR_GOT_PAGE => {
1508 // TODO: relax if possible1506 // TODO: relax if possible
1509 symbol.flags.needs_got = true;1507 symbol.flags.needs_got = true;
1510 },1508 },
1511
1512 .LD64_GOT_LO12_NC,1509 .LD64_GOT_LO12_NC,
1513 .LD64_GOTPAGE_LO15,1510 .LD64_GOTPAGE_LO15,
1514 => {1511 => {
1515 symbol.flags.needs_got = true;1512 symbol.flags.needs_got = true;
1516 },1513 },
1517
1518 .CALL26,1514 .CALL26,
1519 .JUMP26,1515 .JUMP26,
1520 => {1516 => {
...@@ -1522,25 +1518,21 @@ const aarch64 = struct {...@@ -1522,25 +1518,21 @@ const aarch64 = struct {
1522 symbol.flags.needs_plt = true;1518 symbol.flags.needs_plt = true;
1523 }1519 }
1524 },1520 },
1525
1526 .TLSLE_ADD_TPREL_HI12,1521 .TLSLE_ADD_TPREL_HI12,
1527 .TLSLE_ADD_TPREL_LO12_NC,1522 .TLSLE_ADD_TPREL_LO12_NC,
1528 => {1523 => {
1529 if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);1524 if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);
1530 },1525 },
1531
1532 .TLSIE_ADR_GOTTPREL_PAGE21,1526 .TLSIE_ADR_GOTTPREL_PAGE21,
1533 .TLSIE_LD64_GOTTPREL_LO12_NC,1527 .TLSIE_LD64_GOTTPREL_LO12_NC,
1534 => {1528 => {
1535 symbol.flags.needs_gottp = true;1529 symbol.flags.needs_gottp = true;
1536 },1530 },
1537
1538 .TLSGD_ADR_PAGE21,1531 .TLSGD_ADR_PAGE21,
1539 .TLSGD_ADD_LO12_NC,1532 .TLSGD_ADD_LO12_NC,
1540 => {1533 => {
1541 symbol.flags.needs_tlsgd = true;1534 symbol.flags.needs_tlsgd = true;
1542 },1535 },
1543
1544 .TLSDESC_ADR_PAGE21,1536 .TLSDESC_ADR_PAGE21,
1545 .TLSDESC_LD64_LO12,1537 .TLSDESC_LD64_LO12,
1546 .TLSDESC_ADD_LO12,1538 .TLSDESC_ADD_LO12,
...@@ -1551,18 +1543,17 @@ const aarch64 = struct {...@@ -1551,18 +1543,17 @@ const aarch64 = struct {
1551 symbol.flags.needs_tlsdesc = true;1543 symbol.flags.needs_tlsdesc = true;
1552 }1544 }
1553 },1545 },
1554
1555 .ADD_ABS_LO12_NC,1546 .ADD_ABS_LO12_NC,
1556 .ADR_PREL_LO21,1547 .ADR_PREL_LO21,
1557 .LDST8_ABS_LO12_NC,1548 .CONDBR19,
1549 .LDST128_ABS_LO12_NC,
1558 .LDST16_ABS_LO12_NC,1550 .LDST16_ABS_LO12_NC,
1559 .LDST32_ABS_LO12_NC,1551 .LDST32_ABS_LO12_NC,
1560 .LDST64_ABS_LO12_NC,1552 .LDST64_ABS_LO12_NC,
1561 .LDST128_ABS_LO12_NC,1553 .LDST8_ABS_LO12_NC,
1562 .PREL32,1554 .PREL32,
1563 .PREL64,1555 .PREL64,
1564 => {},1556 => {},
1565
1566 else => try atom.reportUnhandledRelocError(rel, elf_file),1557 else => try atom.reportUnhandledRelocError(rel, elf_file),
1567 }1558 }
1568 }1559 }
...@@ -1599,7 +1590,6 @@ const aarch64 = struct {...@@ -1599,7 +1590,6 @@ const aarch64 = struct {
1599 r_offset,1590 r_offset,
1600 );1591 );
1601 },1592 },
1602
1603 .CALL26,1593 .CALL26,
1604 .JUMP26,1594 .JUMP26,
1605 => {1595 => {
...@@ -1611,27 +1601,26 @@ const aarch64 = struct {...@@ -1611,27 +1601,26 @@ const aarch64 = struct {
1611 };1601 };
1612 util.writeBranchImm(disp, code);1602 util.writeBranchImm(disp, code);
1613 },1603 },
16141604 .CONDBR19 => {
1605 const value = math.cast(i19, S + A - P) orelse return error.Overflow;
1606 util.writeCondBrImm(value, code);
1607 },
1615 .PREL32 => {1608 .PREL32 => {
1616 const value = math.cast(i32, S + A - P) orelse return error.Overflow;1609 const value = math.cast(i32, S + A - P) orelse return error.Overflow;
1617 mem.writeInt(u32, code, @bitCast(value), .little);1610 mem.writeInt(u32, code, @bitCast(value), .little);
1618 },1611 },
1619
1620 .PREL64 => {1612 .PREL64 => {
1621 const value = S + A - P;1613 const value = S + A - P;
1622 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);1614 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
1623 },1615 },
1624
1625 .ADR_PREL_LO21 => {1616 .ADR_PREL_LO21 => {
1626 const value = math.cast(i21, S + A - P) orelse return error.Overflow;1617 const value = math.cast(i21, S + A - P) orelse return error.Overflow;
1627 util.writeAdrInst(value, code);1618 util.writeAdrInst(value, code);
1628 },1619 },
1629
1630 .ADR_PREL_PG_HI21 => {1620 .ADR_PREL_PG_HI21 => {
1631 // TODO: check for relaxation of ADRP+ADD1621 // TODO: check for relaxation of ADRP+ADD
1632 util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);1622 util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);
1633 },1623 },
1634
1635 .ADR_GOT_PAGE => if (target.flags.has_got) {1624 .ADR_GOT_PAGE => if (target.flags.has_got) {
1636 util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);1625 util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);
1637 } else {1626 } else {
...@@ -1644,18 +1633,15 @@ const aarch64 = struct {...@@ -1644,18 +1633,15 @@ const aarch64 = struct {
1644 r_offset,1633 r_offset,
1645 });1634 });
1646 },1635 },
1647
1648 .LD64_GOT_LO12_NC => {1636 .LD64_GOT_LO12_NC => {
1649 assert(target.flags.has_got);1637 assert(target.flags.has_got);
1650 const taddr = @as(u64, @intCast(G + GOT + A));1638 const taddr = @as(u64, @intCast(G + GOT + A));
1651 util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);1639 util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
1652 },1640 },
1653
1654 .ADD_ABS_LO12_NC => {1641 .ADD_ABS_LO12_NC => {
1655 const taddr = @as(u64, @intCast(S + A));1642 const taddr = @as(u64, @intCast(S + A));
1656 util.writeAddImmInst(@truncate(taddr), code);1643 util.writeAddImmInst(@truncate(taddr), code);
1657 },1644 },
1658
1659 .LDST8_ABS_LO12_NC,1645 .LDST8_ABS_LO12_NC,
1660 .LDST16_ABS_LO12_NC,1646 .LDST16_ABS_LO12_NC,
1661 .LDST32_ABS_LO12_NC,1647 .LDST32_ABS_LO12_NC,
...@@ -1674,44 +1660,37 @@ const aarch64 = struct {...@@ -1674,44 +1660,37 @@ const aarch64 = struct {
1674 };1660 };
1675 util.writeLoadStoreRegInst(off, code);1661 util.writeLoadStoreRegInst(off, code);
1676 },1662 },
1677
1678 .TLSLE_ADD_TPREL_HI12 => {1663 .TLSLE_ADD_TPREL_HI12 => {
1679 const value = math.cast(i12, (S + A - TP) >> 12) orelse1664 const value = math.cast(i12, (S + A - TP) >> 12) orelse
1680 return error.Overflow;1665 return error.Overflow;
1681 util.writeAddImmInst(@bitCast(value), code);1666 util.writeAddImmInst(@bitCast(value), code);
1682 },1667 },
1683
1684 .TLSLE_ADD_TPREL_LO12_NC => {1668 .TLSLE_ADD_TPREL_LO12_NC => {
1685 const value: i12 = @truncate(S + A - TP);1669 const value: i12 = @truncate(S + A - TP);
1686 util.writeAddImmInst(@bitCast(value), code);1670 util.writeAddImmInst(@bitCast(value), code);
1687 },1671 },
1688
1689 .TLSIE_ADR_GOTTPREL_PAGE21 => {1672 .TLSIE_ADR_GOTTPREL_PAGE21 => {
1690 const S_ = target.gotTpAddress(elf_file);1673 const S_ = target.gotTpAddress(elf_file);
1691 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1674 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1692 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);1675 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
1693 },1676 },
1694
1695 .TLSIE_LD64_GOTTPREL_LO12_NC => {1677 .TLSIE_LD64_GOTTPREL_LO12_NC => {
1696 const S_ = target.gotTpAddress(elf_file);1678 const S_ = target.gotTpAddress(elf_file);
1697 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1679 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1698 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);1680 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1699 util.writeLoadStoreRegInst(off, code);1681 util.writeLoadStoreRegInst(off, code);
1700 },1682 },
1701
1702 .TLSGD_ADR_PAGE21 => {1683 .TLSGD_ADR_PAGE21 => {
1703 const S_ = target.tlsGdAddress(elf_file);1684 const S_ = target.tlsGdAddress(elf_file);
1704 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1685 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1705 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);1686 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
1706 },1687 },
1707
1708 .TLSGD_ADD_LO12_NC => {1688 .TLSGD_ADD_LO12_NC => {
1709 const S_ = target.tlsGdAddress(elf_file);1689 const S_ = target.tlsGdAddress(elf_file);
1710 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1690 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1711 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));1691 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1712 util.writeAddImmInst(off, code);1692 util.writeAddImmInst(off, code);
1713 },1693 },
1714
1715 .TLSDESC_ADR_PAGE21 => {1694 .TLSDESC_ADR_PAGE21 => {
1716 if (target.flags.has_tlsdesc) {1695 if (target.flags.has_tlsdesc) {
1717 const S_ = target.tlsDescAddress(elf_file);1696 const S_ = target.tlsDescAddress(elf_file);
...@@ -1722,7 +1701,6 @@ const aarch64 = struct {...@@ -1722,7 +1701,6 @@ const aarch64 = struct {
1722 util.encoding.Instruction.nop().write(code);1701 util.encoding.Instruction.nop().write(code);
1723 }1702 }
1724 },1703 },
1725
1726 .TLSDESC_LD64_LO12 => {1704 .TLSDESC_LD64_LO12 => {
1727 if (target.flags.has_tlsdesc) {1705 if (target.flags.has_tlsdesc) {
1728 const S_ = target.tlsDescAddress(elf_file);1706 const S_ = target.tlsDescAddress(elf_file);
...@@ -1734,7 +1712,6 @@ const aarch64 = struct {...@@ -1734,7 +1712,6 @@ const aarch64 = struct {
1734 util.encoding.Instruction.nop().write(code);1712 util.encoding.Instruction.nop().write(code);
1735 }1713 }
1736 },1714 },
1737
1738 .TLSDESC_ADD_LO12 => {1715 .TLSDESC_ADD_LO12 => {
1739 if (target.flags.has_tlsdesc) {1716 if (target.flags.has_tlsdesc) {
1740 const S_ = target.tlsDescAddress(elf_file);1717 const S_ = target.tlsDescAddress(elf_file);
...@@ -1747,13 +1724,11 @@ const aarch64 = struct {...@@ -1747,13 +1724,11 @@ const aarch64 = struct {
1747 util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);1724 util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);
1748 }1725 }
1749 },1726 },
1750
1751 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {1727 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
1752 relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});1728 relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});
1753 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));1729 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));
1754 util.encoding.Instruction.movk(.x0, value, .{}).write(code);1730 util.encoding.Instruction.movk(.x0, value, .{}).write(code);
1755 },1731 },
1756
1757 else => try atom.reportUnhandledRelocError(rel, elf_file),1732 else => try atom.reportUnhandledRelocError(rel, elf_file),
1758 }1733 }
1759 }1734 }
src/link/aarch64.zig+6
...@@ -29,6 +29,12 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) void {...@@ -29,6 +29,12 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
29 inst.write(code);29 inst.write(code);
30}30}
3131
32pub fn writeCondBrImm(disp: i19, code: *[4]u8) void {
33 var inst: encoding.Instruction = .read(code);
34 inst.branch_exception_generating_system.conditional_branch_immediate.group.imm19 = @intCast(@shrExact(disp, 2));
35 inst.write(code);
36}
37
32const assert = std.debug.assert;38const assert = std.debug.assert;
33const builtin = @import("builtin");39const builtin = @import("builtin");
34const math = std.math;40const math = std.math;