| ... | @@ -38,6 +38,9 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -38,6 +38,9 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 38 | macho_step.dependOn(testThunks(b, .{ .target = aarch64_target })); | 38 | macho_step.dependOn(testThunks(b, .{ .target = aarch64_target })); |
| 39 | macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target })); | 39 | macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target })); |
| 40 | macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target })); | 40 | macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target })); |
| | 41 | macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target })); |
| | 42 | macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target })); |
| | 43 | macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target })); |
| 41 | macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target })); | 44 | macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target })); |
| 42 | | 45 | |
| 43 | // Tests requiring symlinks when tested on Windows | 46 | // Tests requiring symlinks when tested on Windows |
| ... | @@ -1589,6 +1592,276 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { | ... | @@ -1589,6 +1592,276 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { |
| 1589 | return test_step; | 1592 | return test_step; |
| 1590 | } | 1593 | } |
| 1591 | | 1594 | |
| | 1595 | fn testUnwindInfo(b: *Build, opts: Options) *Step { |
| | 1596 | const test_step = addTestStep(b, "macho-unwind-info", opts); |
| | 1597 | |
| | 1598 | const all_h = all_h: { |
| | 1599 | const wf = WriteFile.create(b); |
| | 1600 | break :all_h wf.add("all.h", |
| | 1601 | \\#ifndef ALL |
| | 1602 | \\#define ALL |
| | 1603 | \\ |
| | 1604 | \\#include <cstddef> |
| | 1605 | \\#include <string> |
| | 1606 | \\#include <stdexcept> |
| | 1607 | \\ |
| | 1608 | \\struct SimpleString { |
| | 1609 | \\ SimpleString(size_t max_size); |
| | 1610 | \\ ~SimpleString(); |
| | 1611 | \\ |
| | 1612 | \\ void print(const char* tag) const; |
| | 1613 | \\ bool append_line(const char* x); |
| | 1614 | \\ |
| | 1615 | \\private: |
| | 1616 | \\ size_t max_size; |
| | 1617 | \\ char* buffer; |
| | 1618 | \\ size_t length; |
| | 1619 | \\}; |
| | 1620 | \\ |
| | 1621 | \\struct SimpleStringOwner { |
| | 1622 | \\ SimpleStringOwner(const char* x); |
| | 1623 | \\ ~SimpleStringOwner(); |
| | 1624 | \\ |
| | 1625 | \\private: |
| | 1626 | \\ SimpleString string; |
| | 1627 | \\}; |
| | 1628 | \\ |
| | 1629 | \\class Error: public std::exception { |
| | 1630 | \\public: |
| | 1631 | \\ explicit Error(const char* msg) : msg{ msg } {} |
| | 1632 | \\ virtual ~Error() noexcept {} |
| | 1633 | \\ virtual const char* what() const noexcept { |
| | 1634 | \\ return msg.c_str(); |
| | 1635 | \\ } |
| | 1636 | \\ |
| | 1637 | \\protected: |
| | 1638 | \\ std::string msg; |
| | 1639 | \\}; |
| | 1640 | \\ |
| | 1641 | \\#endif |
| | 1642 | ); |
| | 1643 | }; |
| | 1644 | |
| | 1645 | const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = |
| | 1646 | \\#include "all.h" |
| | 1647 | \\#include <cstdio> |
| | 1648 | \\ |
| | 1649 | \\void fn_c() { |
| | 1650 | \\ SimpleStringOwner c{ "cccccccccc" }; |
| | 1651 | \\} |
| | 1652 | \\ |
| | 1653 | \\void fn_b() { |
| | 1654 | \\ SimpleStringOwner b{ "b" }; |
| | 1655 | \\ fn_c(); |
| | 1656 | \\} |
| | 1657 | \\ |
| | 1658 | \\int main() { |
| | 1659 | \\ try { |
| | 1660 | \\ SimpleStringOwner a{ "a" }; |
| | 1661 | \\ fn_b(); |
| | 1662 | \\ SimpleStringOwner d{ "d" }; |
| | 1663 | \\ } catch (const Error& e) { |
| | 1664 | \\ printf("Error: %s\n", e.what()); |
| | 1665 | \\ } catch(const std::exception& e) { |
| | 1666 | \\ printf("Exception: %s\n", e.what()); |
| | 1667 | \\ } |
| | 1668 | \\ return 0; |
| | 1669 | \\} |
| | 1670 | }); |
| | 1671 | main_o.root_module.addIncludePath(all_h.dirname()); |
| | 1672 | main_o.linkLibCpp(); |
| | 1673 | |
| | 1674 | const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes = |
| | 1675 | \\#include "all.h" |
| | 1676 | \\#include <cstdio> |
| | 1677 | \\#include <cstring> |
| | 1678 | \\ |
| | 1679 | \\SimpleString::SimpleString(size_t max_size) |
| | 1680 | \\: max_size{ max_size }, length{} { |
| | 1681 | \\ if (max_size == 0) { |
| | 1682 | \\ throw Error{ "Max size must be at least 1." }; |
| | 1683 | \\ } |
| | 1684 | \\ buffer = new char[max_size]; |
| | 1685 | \\ buffer[0] = 0; |
| | 1686 | \\} |
| | 1687 | \\ |
| | 1688 | \\SimpleString::~SimpleString() { |
| | 1689 | \\ delete[] buffer; |
| | 1690 | \\} |
| | 1691 | \\ |
| | 1692 | \\void SimpleString::print(const char* tag) const { |
| | 1693 | \\ printf("%s: %s", tag, buffer); |
| | 1694 | \\} |
| | 1695 | \\ |
| | 1696 | \\bool SimpleString::append_line(const char* x) { |
| | 1697 | \\ const auto x_len = strlen(x); |
| | 1698 | \\ if (x_len + length + 2 > max_size) return false; |
| | 1699 | \\ std::strncpy(buffer + length, x, max_size - length); |
| | 1700 | \\ length += x_len; |
| | 1701 | \\ buffer[length++] = '\n'; |
| | 1702 | \\ buffer[length] = 0; |
| | 1703 | \\ return true; |
| | 1704 | \\} |
| | 1705 | }); |
| | 1706 | simple_string_o.root_module.addIncludePath(all_h.dirname()); |
| | 1707 | simple_string_o.linkLibCpp(); |
| | 1708 | |
| | 1709 | const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes = |
| | 1710 | \\#include "all.h" |
| | 1711 | \\ |
| | 1712 | \\SimpleStringOwner::SimpleStringOwner(const char* x) : string{ 10 } { |
| | 1713 | \\ if (!string.append_line(x)) { |
| | 1714 | \\ throw Error{ "Not enough memory!" }; |
| | 1715 | \\ } |
| | 1716 | \\ string.print("Constructed"); |
| | 1717 | \\} |
| | 1718 | \\ |
| | 1719 | \\SimpleStringOwner::~SimpleStringOwner() { |
| | 1720 | \\ string.print("About to destroy"); |
| | 1721 | \\} |
| | 1722 | }); |
| | 1723 | simple_string_owner_o.root_module.addIncludePath(all_h.dirname()); |
| | 1724 | simple_string_owner_o.linkLibCpp(); |
| | 1725 | |
| | 1726 | const exp_stdout = |
| | 1727 | \\Constructed: a |
| | 1728 | \\Constructed: b |
| | 1729 | \\About to destroy: b |
| | 1730 | \\About to destroy: a |
| | 1731 | \\Error: Not enough memory! |
| | 1732 | \\ |
| | 1733 | ; |
| | 1734 | |
| | 1735 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| | 1736 | exe.addObject(main_o); |
| | 1737 | exe.addObject(simple_string_o); |
| | 1738 | exe.addObject(simple_string_owner_o); |
| | 1739 | exe.linkLibCpp(); |
| | 1740 | |
| | 1741 | const run = addRunArtifact(exe); |
| | 1742 | run.expectStdOutEqual(exp_stdout); |
| | 1743 | test_step.dependOn(&run.step); |
| | 1744 | |
| | 1745 | const check = exe.checkObject(); |
| | 1746 | check.checkInSymtab(); |
| | 1747 | check.checkContains("(was private external) ___gxx_personality_v0"); |
| | 1748 | test_step.dependOn(&check.step); |
| | 1749 | |
| | 1750 | return test_step; |
| | 1751 | } |
| | 1752 | |
| | 1753 | fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step { |
| | 1754 | const test_step = addTestStep(b, "macho-unwind-info-no-subsections-arm64", opts); |
| | 1755 | |
| | 1756 | const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = |
| | 1757 | \\.globl _foo |
| | 1758 | \\.align 4 |
| | 1759 | \\_foo: |
| | 1760 | \\ .cfi_startproc |
| | 1761 | \\ stp x29, x30, [sp, #-32]! |
| | 1762 | \\ .cfi_def_cfa_offset 32 |
| | 1763 | \\ .cfi_offset w30, -24 |
| | 1764 | \\ .cfi_offset w29, -32 |
| | 1765 | \\ mov x29, sp |
| | 1766 | \\ .cfi_def_cfa w29, 32 |
| | 1767 | \\ bl _bar |
| | 1768 | \\ ldp x29, x30, [sp], #32 |
| | 1769 | \\ .cfi_restore w29 |
| | 1770 | \\ .cfi_restore w30 |
| | 1771 | \\ .cfi_def_cfa_offset 0 |
| | 1772 | \\ ret |
| | 1773 | \\ .cfi_endproc |
| | 1774 | \\ |
| | 1775 | \\.globl _bar |
| | 1776 | \\.align 4 |
| | 1777 | \\_bar: |
| | 1778 | \\ .cfi_startproc |
| | 1779 | \\ sub sp, sp, #32 |
| | 1780 | \\ .cfi_def_cfa_offset -32 |
| | 1781 | \\ stp x29, x30, [sp, #16] |
| | 1782 | \\ .cfi_offset w30, -24 |
| | 1783 | \\ .cfi_offset w29, -32 |
| | 1784 | \\ mov x29, sp |
| | 1785 | \\ .cfi_def_cfa w29, 32 |
| | 1786 | \\ mov w0, #4 |
| | 1787 | \\ ldp x29, x30, [sp, #16] |
| | 1788 | \\ .cfi_restore w29 |
| | 1789 | \\ .cfi_restore w30 |
| | 1790 | \\ add sp, sp, #32 |
| | 1791 | \\ .cfi_def_cfa_offset 0 |
| | 1792 | \\ ret |
| | 1793 | \\ .cfi_endproc |
| | 1794 | }); |
| | 1795 | |
| | 1796 | const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = |
| | 1797 | \\#include <stdio.h> |
| | 1798 | \\int foo(); |
| | 1799 | \\int main() { |
| | 1800 | \\ printf("%d\n", foo()); |
| | 1801 | \\ return 0; |
| | 1802 | \\} |
| | 1803 | }); |
| | 1804 | exe.addObject(a_o); |
| | 1805 | |
| | 1806 | const run = addRunArtifact(exe); |
| | 1807 | run.expectStdOutEqual("4\n"); |
| | 1808 | test_step.dependOn(&run.step); |
| | 1809 | |
| | 1810 | return test_step; |
| | 1811 | } |
| | 1812 | |
| | 1813 | fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step { |
| | 1814 | const test_step = addTestStep(b, "macho-unwind-info-no-subsections-x64", opts); |
| | 1815 | |
| | 1816 | const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = |
| | 1817 | \\.globl _foo |
| | 1818 | \\_foo: |
| | 1819 | \\ .cfi_startproc |
| | 1820 | \\ push %rbp |
| | 1821 | \\ .cfi_def_cfa_offset 8 |
| | 1822 | \\ .cfi_offset %rbp, -8 |
| | 1823 | \\ mov %rsp, %rbp |
| | 1824 | \\ .cfi_def_cfa_register %rbp |
| | 1825 | \\ call _bar |
| | 1826 | \\ pop %rbp |
| | 1827 | \\ .cfi_restore %rbp |
| | 1828 | \\ .cfi_def_cfa_offset 0 |
| | 1829 | \\ ret |
| | 1830 | \\ .cfi_endproc |
| | 1831 | \\ |
| | 1832 | \\.globl _bar |
| | 1833 | \\_bar: |
| | 1834 | \\ .cfi_startproc |
| | 1835 | \\ push %rbp |
| | 1836 | \\ .cfi_def_cfa_offset 8 |
| | 1837 | \\ .cfi_offset %rbp, -8 |
| | 1838 | \\ mov %rsp, %rbp |
| | 1839 | \\ .cfi_def_cfa_register %rbp |
| | 1840 | \\ mov $4, %rax |
| | 1841 | \\ pop %rbp |
| | 1842 | \\ .cfi_restore %rbp |
| | 1843 | \\ .cfi_def_cfa_offset 0 |
| | 1844 | \\ ret |
| | 1845 | \\ .cfi_endproc |
| | 1846 | }); |
| | 1847 | |
| | 1848 | const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = |
| | 1849 | \\#include <stdio.h> |
| | 1850 | \\int foo(); |
| | 1851 | \\int main() { |
| | 1852 | \\ printf("%d\n", foo()); |
| | 1853 | \\ return 0; |
| | 1854 | \\} |
| | 1855 | }); |
| | 1856 | exe.addObject(a_o); |
| | 1857 | |
| | 1858 | const run = addRunArtifact(exe); |
| | 1859 | run.expectStdOutEqual("4\n"); |
| | 1860 | test_step.dependOn(&run.step); |
| | 1861 | |
| | 1862 | return test_step; |
| | 1863 | } |
| | 1864 | |
| 1592 | // Adapted from https://github.com/llvm/llvm-project/blob/main/lld/test/MachO/weak-binding.s | 1865 | // Adapted from https://github.com/llvm/llvm-project/blob/main/lld/test/MachO/weak-binding.s |
| 1593 | fn testWeakBind(b: *Build, opts: Options) *Step { | 1866 | fn testWeakBind(b: *Build, opts: Options) *Step { |
| 1594 | const test_step = addTestStep(b, "macho-weak-bind", opts); | 1867 | const test_step = addTestStep(b, "macho-weak-bind", opts); |