| ... | ... | @@ -857,8 +857,6 @@ pub const PltSection = struct { |
| 857 | 857 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 858 | 858 | output_symtab_ctx: Elf.SymtabCtx = .{}, |
| 859 | 859 | |
| 860 | | pub const preamble_size = 32; |
| 861 | | |
| 862 | 860 | pub fn deinit(plt: *PltSection, allocator: Allocator) void { |
| 863 | 861 | plt.symbols.deinit(allocator); |
| 864 | 862 | } |
| ... | ... | @@ -877,39 +875,33 @@ pub const PltSection = struct { |
| 877 | 875 | try plt.symbols.append(gpa, sym_index); |
| 878 | 876 | } |
| 879 | 877 | |
| 880 | | pub fn size(plt: PltSection) usize { |
| 881 | | return preamble_size + plt.symbols.items.len * 16; |
| 878 | pub fn size(plt: PltSection, elf_file: *Elf) usize { |
| 879 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 880 | return preambleSize(cpu_arch) + plt.symbols.items.len * entrySize(cpu_arch); |
| 882 | 881 | } |
| 883 | 882 | |
| 884 | | pub fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { |
| 885 | | const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; |
| 886 | | const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; |
| 887 | | var preamble = [_]u8{ |
| 888 | | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 |
| 889 | | 0x41, 0x53, // push r11 |
| 890 | | 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push qword ptr [rip] -> .got.plt[1] |
| 891 | | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[2] |
| 883 | pub fn preambleSize(cpu_arch: std.Target.Cpu.Arch) usize { |
| 884 | return switch (cpu_arch) { |
| 885 | .x86_64 => 32, |
| 886 | .aarch64 => 8 * @sizeOf(u32), |
| 887 | else => @panic("TODO implement preambleSize for this cpu arch"), |
| 892 | 888 | }; |
| 893 | | var disp = @as(i64, @intCast(got_plt_addr + 8)) - @as(i64, @intCast(plt_addr + 8)) - 4; |
| 894 | | mem.writeInt(i32, preamble[8..][0..4], @as(i32, @intCast(disp)), .little); |
| 895 | | disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4; |
| 896 | | mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little); |
| 897 | | try writer.writeAll(&preamble); |
| 898 | | try writer.writeByteNTimes(0xcc, preamble_size - preamble.len); |
| 899 | | |
| 900 | | for (plt.symbols.items, 0..) |sym_index, i| { |
| 901 | | const sym = elf_file.symbol(sym_index); |
| 902 | | const target_addr = sym.gotPltAddress(elf_file); |
| 903 | | const source_addr = sym.pltAddress(elf_file); |
| 904 | | disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4; |
| 905 | | var entry = [_]u8{ |
| 906 | | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 |
| 907 | | 0x41, 0xbb, 0x00, 0x00, 0x00, 0x00, // mov r11d, N |
| 908 | | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[N] |
| 909 | | }; |
| 910 | | mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(i)), .little); |
| 911 | | mem.writeInt(i32, entry[12..][0..4], @as(i32, @intCast(disp)), .little); |
| 912 | | try writer.writeAll(&entry); |
| 889 | } |
| 890 | |
| 891 | pub fn entrySize(cpu_arch: std.Target.Cpu.Arch) usize { |
| 892 | return switch (cpu_arch) { |
| 893 | .x86_64 => 16, |
| 894 | .aarch64 => 4 * @sizeOf(u32), |
| 895 | else => @panic("TODO implement entrySize for this cpu arch"), |
| 896 | }; |
| 897 | } |
| 898 | |
| 899 | pub fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { |
| 900 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 901 | switch (cpu_arch) { |
| 902 | .x86_64 => try x86_64.write(plt, elf_file, writer), |
| 903 | .aarch64 => try aarch64.write(plt, elf_file, writer), |
| 904 | else => return error.UnsupportedCpuArch, |
| 913 | 905 | } |
| 914 | 906 | } |
| 915 | 907 | |
| ... | ... | @@ -946,6 +938,7 @@ pub const PltSection = struct { |
| 946 | 938 | } |
| 947 | 939 | |
| 948 | 940 | pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void { |
| 941 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 949 | 942 | for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |sym_index, ilocal| { |
| 950 | 943 | const sym = elf_file.symbol(sym_index); |
| 951 | 944 | const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); |
| ... | ... | @@ -958,7 +951,7 @@ pub const PltSection = struct { |
| 958 | 951 | .st_other = 0, |
| 959 | 952 | .st_shndx = @intCast(elf_file.plt_section_index.?), |
| 960 | 953 | .st_value = sym.pltAddress(elf_file), |
| 961 | | .st_size = 16, |
| 954 | .st_size = entrySize(cpu_arch), |
| 962 | 955 | }; |
| 963 | 956 | } |
| 964 | 957 | } |
| ... | ... | @@ -992,6 +985,97 @@ pub const PltSection = struct { |
| 992 | 985 | }); |
| 993 | 986 | } |
| 994 | 987 | } |
| 988 | |
| 989 | const x86_64 = struct { |
| 990 | fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { |
| 991 | const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; |
| 992 | const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; |
| 993 | var preamble = [_]u8{ |
| 994 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 |
| 995 | 0x41, 0x53, // push r11 |
| 996 | 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push qword ptr [rip] -> .got.plt[1] |
| 997 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[2] |
| 998 | }; |
| 999 | var disp = @as(i64, @intCast(got_plt_addr + 8)) - @as(i64, @intCast(plt_addr + 8)) - 4; |
| 1000 | mem.writeInt(i32, preamble[8..][0..4], @as(i32, @intCast(disp)), .little); |
| 1001 | disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4; |
| 1002 | mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little); |
| 1003 | try writer.writeAll(&preamble); |
| 1004 | try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len); |
| 1005 | |
| 1006 | for (plt.symbols.items, 0..) |sym_index, i| { |
| 1007 | const sym = elf_file.symbol(sym_index); |
| 1008 | const target_addr = sym.gotPltAddress(elf_file); |
| 1009 | const source_addr = sym.pltAddress(elf_file); |
| 1010 | disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4; |
| 1011 | var entry = [_]u8{ |
| 1012 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 |
| 1013 | 0x41, 0xbb, 0x00, 0x00, 0x00, 0x00, // mov r11d, N |
| 1014 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[N] |
| 1015 | }; |
| 1016 | mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(i)), .little); |
| 1017 | mem.writeInt(i32, entry[12..][0..4], @as(i32, @intCast(disp)), .little); |
| 1018 | try writer.writeAll(&entry); |
| 1019 | } |
| 1020 | } |
| 1021 | }; |
| 1022 | |
| 1023 | const aarch64 = struct { |
| 1024 | fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { |
| 1025 | { |
| 1026 | const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; |
| 1027 | const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; |
| 1028 | // TODO: relax if possible |
| 1029 | // .got.plt[2] |
| 1030 | const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16); |
| 1031 | const ldr_off = try aarch64_util.calcPageOffset(.load_store_64, got_plt_addr + 16); |
| 1032 | const add_off = try aarch64_util.calcPageOffset(.arithmetic, got_plt_addr + 16); |
| 1033 | |
| 1034 | const preamble = &[_]Instruction{ |
| 1035 | Instruction.stp( |
| 1036 | .x16, |
| 1037 | .x30, |
| 1038 | Register.sp, |
| 1039 | Instruction.LoadStorePairOffset.pre_index(-16), |
| 1040 | ), |
| 1041 | Instruction.adrp(.x16, pages), |
| 1042 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), |
| 1043 | Instruction.add(.x16, .x16, add_off, false), |
| 1044 | Instruction.br(.x17), |
| 1045 | Instruction.nop(), |
| 1046 | Instruction.nop(), |
| 1047 | Instruction.nop(), |
| 1048 | }; |
| 1049 | comptime assert(preamble.len == 8); |
| 1050 | for (preamble) |inst| { |
| 1051 | try writer.writeInt(u32, inst.toU32(), .little); |
| 1052 | } |
| 1053 | } |
| 1054 | |
| 1055 | for (plt.symbols.items) |sym_index| { |
| 1056 | const sym = elf_file.symbol(sym_index); |
| 1057 | const target_addr = sym.gotPltAddress(elf_file); |
| 1058 | const source_addr = sym.pltAddress(elf_file); |
| 1059 | const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); |
| 1060 | const ldr_off = try aarch64_util.calcPageOffset(.load_store_64, target_addr); |
| 1061 | const add_off = try aarch64_util.calcPageOffset(.arithmetic, target_addr); |
| 1062 | const insts = &[_]Instruction{ |
| 1063 | Instruction.adrp(.x16, pages), |
| 1064 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), |
| 1065 | Instruction.add(.x16, .x16, add_off, false), |
| 1066 | Instruction.br(.x17), |
| 1067 | }; |
| 1068 | comptime assert(insts.len == 4); |
| 1069 | for (insts) |inst| { |
| 1070 | try writer.writeInt(u32, inst.toU32(), .little); |
| 1071 | } |
| 1072 | } |
| 1073 | } |
| 1074 | |
| 1075 | const aarch64_util = @import("../aarch64.zig"); |
| 1076 | const Instruction = aarch64_util.Instruction; |
| 1077 | const Register = aarch64_util.Register; |
| 1078 | }; |
| 995 | 1079 | }; |
| 996 | 1080 | |
| 997 | 1081 | pub const GotPltSection = struct { |