From 8a1c047c0d6a51c993188415109cf37069ad750e Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Sun, 8 Sep 2024 12:03:04 -0700 Subject: [PATCH] Compilation: Add driver/frontend support for pic/pie options --- src/aro/Compilation.zig | 23 ++++++++++++++++++++++- src/aro/Driver.zig | 31 +++++++++++++++++++++++++++++++ src/aro/target.zig | 7 +++++++ src/backend.zig | 1 + src/backend/CodeGenOptions.zig | 27 +++++++++++++++++++++++++++ test/cases/pic1.c | 7 +++++++ test/cases/pic2.c | 7 +++++++ test/cases/pie1.c | 6 ++++++ test/cases/pie2.c | 6 ++++++ 9 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/backend/CodeGenOptions.zig create mode 100644 test/cases/pic1.c create mode 100644 test/cases/pic2.c create mode 100644 test/cases/pie1.c create mode 100644 test/cases/pie2.c diff --git a/src/aro/Compilation.zig b/src/aro/Compilation.zig index f1f5585f..71a623f5 100644 --- a/src/aro/Compilation.zig +++ b/src/aro/Compilation.zig @@ -3,7 +3,9 @@ const Allocator = mem.Allocator; const assert = std.debug.assert; const EpochSeconds = std.time.epoch.EpochSeconds; const mem = std.mem; -const Interner = @import("backend").Interner; +const backend = @import("backend"); +const Interner = backend.Interner; +const CodeGenOptions = backend.CodeGenOptions; const Builtins = @import("Builtins.zig"); const Builtin = Builtins.Builtin; const Diagnostics = @import("Diagnostics.zig"); @@ -92,6 +94,7 @@ const Compilation = @This(); gpa: Allocator, diagnostics: Diagnostics, +code_gen_options: CodeGenOptions = .default, environment: Environment = .{}, sources: std.StringArrayHashMapUnmanaged(Source) = .{}, include_dirs: std.ArrayListUnmanaged([]const u8) = .{}, @@ -527,6 +530,24 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void { \\#define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__ \\ ); + + switch (comp.code_gen_options.pic_level) { + .none => {}, + .one, .two => { + try w.print( + \\#define __pic__ {0d} + \\#define __PIC__ {0d} + \\ + , .{@intFromEnum(comp.code_gen_options.pic_level)}); + if (comp.code_gen_options.is_pie) { + try w.print( + \\#define __pie__ {0d} + \\#define __PIE__ {0d} + \\ + , .{@intFromEnum(comp.code_gen_options.pic_level)}); + } + }, + } } /// Generate builtin macros that will be available to each source file. diff --git a/src/aro/Driver.zig b/src/aro/Driver.zig index f7834536..50a51b4f 100644 --- a/src/aro/Driver.zig +++ b/src/aro/Driver.zig @@ -47,6 +47,8 @@ color: ?bool = null, nobuiltininc: bool = false, nostdinc: bool = false, nostdlibinc: bool = false, +desired_pic_level: ?backend.CodeGenOptions.PicLevel = null, +desired_pie_level: ?backend.CodeGenOptions.PicLevel = null, debug_dump_letters: packed struct(u3) { d: bool = false, m: bool = false, @@ -115,6 +117,8 @@ pub const usage = \\ -fno-char8_t Disable char8_t (disabled by default for pre-C23) \\ -fcolor-diagnostics Enable colors in diagnostics \\ -fno-color-diagnostics Disable colors in diagnostics + \\ -fcommon Place uninitialized global variables in a common block + \\ -fno-common Place uninitialized global variables in the BSS section of the object file \\ -fdeclspec Enable support for __declspec attributes \\ -fgnuc-version= Controls value of __GNUC__ and related macros. Set to 0 or empty to disable them. \\ -fno-declspec Disable support for __declspec attributes @@ -135,6 +139,10 @@ pub const usage = \\ -fnative-half-type Use the native half type for __fp16 instead of promoting to float \\ -fnative-half-arguments-and-returns \\ Allow half-precision function arguments and return values + \\ -fpic Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine + \\ -fPIC Similar to -fpic but avoid any limit on the size of the global offset table + \\ -fpie Similar to -fpic, but the generated position-independent code can only be linked into executables + \\ -fPIE Similar to -fPIC, but the generated position-independent code can only be linked into executables \\ -fshort-enums Use the narrowest possible integer type for enums \\ -fno-short-enums Use "int" as the tag type for enums \\ -fsigned-char "char" is signed @@ -273,6 +281,10 @@ pub fn parseArgs( d.color = true; } else if (mem.eql(u8, arg, "-fno-color-diagnostics")) { d.color = false; + } else if (mem.eql(u8, arg, "-fcommon")) { + d.comp.code_gen_options.common = true; + } else if (mem.eql(u8, arg, "-fno-common")) { + d.comp.code_gen_options.common = false; } else if (mem.eql(u8, arg, "-fdollars-in-identifiers")) { d.comp.langopts.dollars_in_identifiers = true; } else if (mem.eql(u8, arg, "-fno-dollars-in-identifiers")) { @@ -297,6 +309,21 @@ pub fn parseArgs( d.comp.langopts.use_native_half_type = true; } else if (mem.eql(u8, arg, "-fnative-half-arguments-and-returns")) { d.comp.langopts.allow_half_args_and_returns = true; + } else if (mem.eql(u8, arg, "-fno-pic") or mem.eql(u8, arg, "-fno-PIC") or mem.eql(u8, arg, "-fno-pie") or mem.eql(u8, arg, "-fno-PIE")) { + d.desired_pic_level = .none; + d.desired_pie_level = .none; + } else if (mem.eql(u8, arg, "-fpic")) { + d.desired_pic_level = .one; + d.desired_pie_level = .none; + } else if (mem.eql(u8, arg, "-fPIC")) { + d.desired_pic_level = .two; + d.desired_pie_level = .none; + } else if (mem.eql(u8, arg, "-fpie")) { + d.desired_pic_level = .one; + d.desired_pie_level = .one; + } else if (mem.eql(u8, arg, "-fPIE")) { + d.desired_pic_level = .two; + d.desired_pie_level = .two; } else if (mem.eql(u8, arg, "-fshort-enums")) { d.comp.langopts.short_enums = true; } else if (mem.eql(u8, arg, "-fno-short-enums")) { @@ -507,6 +534,10 @@ pub fn parseArgs( return d.fatal("invalid value '{0s}' in '-fgnuc-version={0s}'", .{gnuc_version}); } d.comp.langopts.gnuc_version = version.toUnsigned(); + const wants_pie: ?bool = if (d.desired_pie_level) |level| level != .none else null; + const pic_level, const is_pie = target_util.getPICMode(d.comp.target, d.desired_pic_level, wants_pie); + d.comp.code_gen_options.pic_level = pic_level; + d.comp.code_gen_options.is_pie = is_pie; return false; } diff --git a/src/aro/target.zig b/src/aro/target.zig index 7b2e1576..5ee665c5 100644 --- a/src/aro/target.zig +++ b/src/aro/target.zig @@ -2,6 +2,7 @@ const std = @import("std"); const LangOpts = @import("LangOpts.zig"); const Type = @import("Type.zig"); const TargetSet = @import("Builtins/Properties.zig").TargetSet; +const backend = @import("backend"); /// intmax_t for this target pub fn intMaxType(target: std.Target) Type { @@ -722,6 +723,12 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 { return stream.getWritten(); } +/// This currently just returns the desired settings without considering target defaults / requirements +pub fn getPICMode(target: std.Target, desired_pic_level: ?backend.CodeGenOptions.PicLevel, wants_pie: ?bool) struct { backend.CodeGenOptions.PicLevel, bool } { + _ = target; + return .{ desired_pic_level orelse .none, wants_pie orelse false }; +} + test "alignment functions - smoke test" { var target: std.Target = undefined; const x86 = std.Target.Cpu.Arch.x86_64; diff --git a/src/backend.zig b/src/backend.zig index cf938b95..24f4e27f 100644 --- a/src/backend.zig +++ b/src/backend.zig @@ -1,6 +1,7 @@ pub const Interner = @import("backend/Interner.zig"); pub const Ir = @import("backend/Ir.zig"); pub const Object = @import("backend/Object.zig"); +pub const CodeGenOptions = @import("backend/CodeGenOptions.zig"); pub const CallingConvention = enum { C, diff --git a/src/backend/CodeGenOptions.zig b/src/backend/CodeGenOptions.zig new file mode 100644 index 00000000..9e0ffc9a --- /dev/null +++ b/src/backend/CodeGenOptions.zig @@ -0,0 +1,27 @@ +/// place uninitialized global variables in a common block +common: bool, +/// Place each function into its own section in the output file if the target supports arbitrary sections +func_sections: bool, +/// Place each data item into its own section in the output file if the target supports arbitrary sections +data_sections: bool, +pic_level: PicLevel, +/// Generate position-independent code that can only be linked into executables +is_pie: bool, + +pub const PicLevel = enum(u8) { + /// Do not generate position-independent code + none = 0, + /// Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine. + one = 1, + /// If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding + /// any limit on the size of the global offset table. + two = 2, +}; + +pub const default: @This() = .{ + .common = false, + .func_sections = false, + .data_sections = false, + .pic_level = .none, + .is_pie = false, +}; diff --git a/test/cases/pic1.c b/test/cases/pic1.c new file mode 100644 index 00000000..f320e1a7 --- /dev/null +++ b/test/cases/pic1.c @@ -0,0 +1,7 @@ +//aro-args --target=x86_64-linux-gnu -fpic + +_Static_assert(__pic__ == 1, ""); +_Static_assert(__PIC__ == 1, ""); +#if defined __pie__ || defined __PIE__ +#error __pie__ and __PIE__ should not be defined +#endif diff --git a/test/cases/pic2.c b/test/cases/pic2.c new file mode 100644 index 00000000..2fdaf5dd --- /dev/null +++ b/test/cases/pic2.c @@ -0,0 +1,7 @@ +//aro-args --target=x86_64-linux-gnu -fPIC + +_Static_assert(__pic__ == 2, ""); +_Static_assert(__PIC__ == 2, ""); +#if defined __pie__ || defined __PIE__ +#error __pie__ and __PIE__ should not be defined +#endif diff --git a/test/cases/pie1.c b/test/cases/pie1.c new file mode 100644 index 00000000..5652b1d3 --- /dev/null +++ b/test/cases/pie1.c @@ -0,0 +1,6 @@ +//aro-args --target=x86_64-linux-gnu -fpie + +_Static_assert(__pic__ == 1, ""); +_Static_assert(__PIC__ == 1, ""); +_Static_assert(__pie__ == 1, ""); +_Static_assert(__PIE__ == 1, ""); diff --git a/test/cases/pie2.c b/test/cases/pie2.c new file mode 100644 index 00000000..9c706f90 --- /dev/null +++ b/test/cases/pie2.c @@ -0,0 +1,6 @@ +//aro-args --target=x86_64-linux-gnu -fPIE + +_Static_assert(__pic__ == 2, ""); +_Static_assert(__PIC__ == 2, ""); +_Static_assert(__pie__ == 2, ""); +_Static_assert(__PIE__ == 2, "");