| ... | @@ -857,8 +857,6 @@ pub const PltSection = struct { | ... | @@ -857,8 +857,6 @@ pub const PltSection = struct { |
| 857 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 857 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 858 | output_symtab_ctx: Elf.SymtabCtx = .{}, | 858 | output_symtab_ctx: Elf.SymtabCtx = .{}, |
| 859 | | 859 | |
| 860 | pub const preamble_size = 32; | | |
| 861 | | | |
| 862 | pub fn deinit(plt: *PltSection, allocator: Allocator) void { | 860 | pub fn deinit(plt: *PltSection, allocator: Allocator) void { |
| 863 | plt.symbols.deinit(allocator); | 861 | plt.symbols.deinit(allocator); |
| 864 | } | 862 | } |
| ... | @@ -877,39 +875,33 @@ pub const PltSection = struct { | ... | @@ -877,39 +875,33 @@ pub const PltSection = struct { |
| 877 | try plt.symbols.append(gpa, sym_index); | 875 | try plt.symbols.append(gpa, sym_index); |
| 878 | } | 876 | } |
| 879 | | 877 | |
| 880 | pub fn size(plt: PltSection) usize { | 878 | pub fn size(plt: PltSection, elf_file: *Elf) usize { |
| 881 | return preamble_size + plt.symbols.items.len * 16; | 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 { | 883 | pub fn preambleSize(cpu_arch: std.Target.Cpu.Arch) usize { |
| 885 | const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; | 884 | return switch (cpu_arch) { |
| 886 | const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; | 885 | .x86_64 => 32, |
| 887 | var preamble = [_]u8{ | 886 | .aarch64 => 8 * @sizeOf(u32), |
| 888 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 | 887 | else => @panic("TODO implement preambleSize for this cpu arch"), |
| 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] | | |
| 892 | }; | 888 | }; |
| 893 | var disp = @as(i64, @intCast(got_plt_addr + 8)) - @as(i64, @intCast(plt_addr + 8)) - 4; | 889 | } |
| 894 | mem.writeInt(i32, preamble[8..][0..4], @as(i32, @intCast(disp)), .little); | 890 | |
| 895 | disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4; | 891 | pub fn entrySize(cpu_arch: std.Target.Cpu.Arch) usize { |
| 896 | mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little); | 892 | return switch (cpu_arch) { |
| 897 | try writer.writeAll(&preamble); | 893 | .x86_64 => 16, |
| 898 | try writer.writeByteNTimes(0xcc, preamble_size - preamble.len); | 894 | .aarch64 => 4 * @sizeOf(u32), |
| 899 | | 895 | else => @panic("TODO implement entrySize for this cpu arch"), |
| 900 | for (plt.symbols.items, 0..) |sym_index, i| { | 896 | }; |
| 901 | const sym = elf_file.symbol(sym_index); | 897 | } |
| 902 | const target_addr = sym.gotPltAddress(elf_file); | 898 | |
| 903 | const source_addr = sym.pltAddress(elf_file); | 899 | pub fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { |
| 904 | disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4; | 900 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 905 | var entry = [_]u8{ | 901 | switch (cpu_arch) { |
| 906 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 | 902 | .x86_64 => try x86_64.write(plt, elf_file, writer), |
| 907 | 0x41, 0xbb, 0x00, 0x00, 0x00, 0x00, // mov r11d, N | 903 | .aarch64 => try aarch64.write(plt, elf_file, writer), |
| 908 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[N] | 904 | else => return error.UnsupportedCpuArch, |
| 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); | | |
| 913 | } | 905 | } |
| 914 | } | 906 | } |
| 915 | | 907 | |
| ... | @@ -946,6 +938,7 @@ pub const PltSection = struct { | ... | @@ -946,6 +938,7 @@ pub const PltSection = struct { |
| 946 | } | 938 | } |
| 947 | | 939 | |
| 948 | pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void { | 940 | pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void { |
| | 941 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 949 | for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |sym_index, ilocal| { | 942 | for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |sym_index, ilocal| { |
| 950 | const sym = elf_file.symbol(sym_index); | 943 | const sym = elf_file.symbol(sym_index); |
| 951 | const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); | 944 | const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); |
| ... | @@ -958,7 +951,7 @@ pub const PltSection = struct { | ... | @@ -958,7 +951,7 @@ pub const PltSection = struct { |
| 958 | .st_other = 0, | 951 | .st_other = 0, |
| 959 | .st_shndx = @intCast(elf_file.plt_section_index.?), | 952 | .st_shndx = @intCast(elf_file.plt_section_index.?), |
| 960 | .st_value = sym.pltAddress(elf_file), | 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,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 | pub const GotPltSection = struct { | 1081 | pub const GotPltSection = struct { |