authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-31 23:05:01+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-31 23:05:01+02:00
log50db993119d9b1031700be94b757eaf100f35857
treeb13b39d4942b5129aaa0ff37f6df36d740996d5d
parent2831d6e9b8b29c21bc7417c5e370674e3130f6ae

macho: fix allocating sections within segment when parsing objects


4 files changed, 551 insertions(+), 603 deletions(-)

lib/std/macho.zig+20-20
...@@ -601,35 +601,35 @@ pub const segment_command = extern struct {...@@ -601,35 +601,35 @@ pub const segment_command = extern struct {
601/// command and their size is reflected in cmdsize.601/// command and their size is reflected in cmdsize.
602pub const segment_command_64 = extern struct {602pub const segment_command_64 = extern struct {
603 /// LC_SEGMENT_64603 /// LC_SEGMENT_64
604 cmd: u32,604 cmd: u32 = LC_SEGMENT_64,
605605
606 /// includes sizeof section_64 structs606 /// includes sizeof section_64 structs
607 cmdsize: u32,607 cmdsize: u32 = @sizeOf(segment_command_64),
608608
609 /// segment name609 /// segment name
610 segname: [16]u8,610 segname: [16]u8,
611611
612 /// memory address of this segment612 /// memory address of this segment
613 vmaddr: u64,613 vmaddr: u64 = 0,
614614
615 /// memory size of this segment615 /// memory size of this segment
616 vmsize: u64,616 vmsize: u64 = 0,
617617
618 /// file offset of this segment618 /// file offset of this segment
619 fileoff: u64,619 fileoff: u64 = 0,
620620
621 /// amount to map from the file621 /// amount to map from the file
622 filesize: u64,622 filesize: u64 = 0,
623623
624 /// maximum VM protection624 /// maximum VM protection
625 maxprot: vm_prot_t,625 maxprot: vm_prot_t = VM_PROT_NONE,
626626
627 /// initial VM protection627 /// initial VM protection
628 initprot: vm_prot_t,628 initprot: vm_prot_t = VM_PROT_NONE,
629629
630 /// number of sections in segment630 /// number of sections in segment
631 nsects: u32,631 nsects: u32 = 0,
632 flags: u32,632 flags: u32 = 0,
633};633};
634634
635/// A segment is made up of zero or more sections. Non-MH_OBJECT files have635/// A segment is made up of zero or more sections. Non-MH_OBJECT files have
...@@ -700,34 +700,34 @@ pub const section_64 = extern struct {...@@ -700,34 +700,34 @@ pub const section_64 = extern struct {
700 segname: [16]u8,700 segname: [16]u8,
701701
702 /// memory address of this section702 /// memory address of this section
703 addr: u64,703 addr: u64 = 0,
704704
705 /// size in bytes of this section705 /// size in bytes of this section
706 size: u64,706 size: u64 = 0,
707707
708 /// file offset of this section708 /// file offset of this section
709 offset: u32,709 offset: u32 = 0,
710710
711 /// section alignment (power of 2)711 /// section alignment (power of 2)
712 @"align": u32,712 @"align": u32 = 0,
713713
714 /// file offset of relocation entries714 /// file offset of relocation entries
715 reloff: u32,715 reloff: u32 = 0,
716716
717 /// number of relocation entries717 /// number of relocation entries
718 nreloc: u32,718 nreloc: u32 = 0,
719719
720 /// flags (section type and attributes720 /// flags (section type and attributes
721 flags: u32,721 flags: u32 = S_REGULAR,
722722
723 /// reserved (for offset or index)723 /// reserved (for offset or index)
724 reserved1: u32,724 reserved1: u32 = 0,
725725
726 /// reserved (for count or sizeof)726 /// reserved (for count or sizeof)
727 reserved2: u32,727 reserved2: u32 = 0,
728728
729 /// reserved729 /// reserved
730 reserved3: u32,730 reserved3: u32 = 0,
731};731};
732732
733pub const nlist = extern struct {733pub const nlist = extern struct {
src/link/MachO.zig+449-403
...@@ -1133,20 +1133,19 @@ pub const MatchingSection = struct {...@@ -1133,20 +1133,19 @@ pub const MatchingSection = struct {
1133};1133};
11341134
1135pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSection {1135pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSection {
1136 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1137 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1138 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1139 const segname = commands.segmentName(sect);1136 const segname = commands.segmentName(sect);
1140 const sectname = commands.sectionName(sect);1137 const sectname = commands.sectionName(sect);
1141
1142 var needs_allocation = false;
1143 const res: ?MatchingSection = blk: {1138 const res: ?MatchingSection = blk: {
1144 switch (commands.sectionType(sect)) {1139 switch (commands.sectionType(sect)) {
1145 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {1140 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
1146 if (self.text_const_section_index == null) {1141 if (self.text_const_section_index == null) {
1147 self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);1142 self.text_const_section_index = try self.allocateSection(
1148 try text_seg.addSection(self.base.allocator, "__const", .{});1143 self.text_segment_cmd_index.?,
1149 needs_allocation = true;1144 "__const",
1145 sect.size,
1146 sect.@"align",
1147 .{},
1148 );
1150 }1149 }
11511150
1152 break :blk .{1151 break :blk .{
...@@ -1159,11 +1158,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1159,11 +1158,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1159 // TODO it seems the common values within the sections in objects are deduplicated/merged1158 // TODO it seems the common values within the sections in objects are deduplicated/merged
1160 // on merging the sections' contents.1159 // on merging the sections' contents.
1161 if (self.objc_methname_section_index == null) {1160 if (self.objc_methname_section_index == null) {
1162 self.objc_methname_section_index = @intCast(u16, text_seg.sections.items.len);1161 self.objc_methname_section_index = try self.allocateSection(
1163 try text_seg.addSection(self.base.allocator, "__objc_methname", .{1162 self.text_segment_cmd_index.?,
1164 .flags = macho.S_CSTRING_LITERALS,1163 "__objc_methname",
1165 });1164 sect.size,
1166 needs_allocation = true;1165 sect.@"align",
1166 .{},
1167 );
1167 }1168 }
11681169
1169 break :blk .{1170 break :blk .{
...@@ -1172,11 +1173,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1172,11 +1173,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1172 };1173 };
1173 } else if (mem.eql(u8, sectname, "__objc_methtype")) {1174 } else if (mem.eql(u8, sectname, "__objc_methtype")) {
1174 if (self.objc_methtype_section_index == null) {1175 if (self.objc_methtype_section_index == null) {
1175 self.objc_methtype_section_index = @intCast(u16, text_seg.sections.items.len);1176 self.objc_methtype_section_index = try self.allocateSection(
1176 try text_seg.addSection(self.base.allocator, "__objc_methtype", .{1177 self.text_segment_cmd_index.?,
1177 .flags = macho.S_CSTRING_LITERALS,1178 "__objc_methtype",
1178 });1179 sect.size,
1179 needs_allocation = true;1180 sect.@"align",
1181 .{},
1182 );
1180 }1183 }
11811184
1182 break :blk .{1185 break :blk .{
...@@ -1185,9 +1188,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1185,9 +1188,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1185 };1188 };
1186 } else if (mem.eql(u8, sectname, "__objc_classname")) {1189 } else if (mem.eql(u8, sectname, "__objc_classname")) {
1187 if (self.objc_classname_section_index == null) {1190 if (self.objc_classname_section_index == null) {
1188 self.objc_classname_section_index = @intCast(u16, text_seg.sections.items.len);1191 self.objc_classname_section_index = try self.allocateSection(
1189 try text_seg.addSection(self.base.allocator, "__objc_classname", .{});1192 self.text_segment_cmd_index.?,
1190 needs_allocation = true;1193 "__objc_classname",
1194 sect.size,
1195 sect.@"align",
1196 .{},
1197 );
1191 }1198 }
11921199
1193 break :blk .{1200 break :blk .{
...@@ -1197,11 +1204,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1197,11 +1204,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1197 }1204 }
11981205
1199 if (self.cstring_section_index == null) {1206 if (self.cstring_section_index == null) {
1200 self.cstring_section_index = @intCast(u16, text_seg.sections.items.len);1207 self.cstring_section_index = try self.allocateSection(
1201 try text_seg.addSection(self.base.allocator, "__cstring", .{1208 self.text_segment_cmd_index.?,
1202 .flags = macho.S_CSTRING_LITERALS,1209 "__cstring",
1203 });1210 sect.size,
1204 needs_allocation = true;1211 sect.@"align",
1212 .{
1213 .flags = macho.S_CSTRING_LITERALS,
1214 },
1215 );
1205 }1216 }
12061217
1207 break :blk .{1218 break :blk .{
...@@ -1212,29 +1223,37 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1212,29 +1223,37 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1212 macho.S_LITERAL_POINTERS => {1223 macho.S_LITERAL_POINTERS => {
1213 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {1224 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {
1214 if (self.objc_selrefs_section_index == null) {1225 if (self.objc_selrefs_section_index == null) {
1215 self.objc_selrefs_section_index = @intCast(u16, data_seg.sections.items.len);1226 self.objc_selrefs_section_index = try self.allocateSection(
1216 try data_seg.addSection(self.base.allocator, "__objc_selrefs", .{1227 self.data_segment_cmd_index.?,
1217 .flags = macho.S_LITERAL_POINTERS,1228 "__objc_selrefs",
1218 });1229 sect.size,
1219 needs_allocation = true;1230 sect.@"align",
1231 .{
1232 .flags = macho.S_LITERAL_POINTERS,
1233 },
1234 );
1220 }1235 }
12211236
1222 break :blk .{1237 break :blk .{
1223 .seg = self.data_segment_cmd_index.?,1238 .seg = self.data_segment_cmd_index.?,
1224 .sect = self.objc_selrefs_section_index.?,1239 .sect = self.objc_selrefs_section_index.?,
1225 };1240 };
1241 } else {
1242 // TODO investigate
1243 break :blk null;
1226 }1244 }
1227
1228 // TODO investigate
1229 break :blk null;
1230 },1245 },
1231 macho.S_MOD_INIT_FUNC_POINTERS => {1246 macho.S_MOD_INIT_FUNC_POINTERS => {
1232 if (self.mod_init_func_section_index == null) {1247 if (self.mod_init_func_section_index == null) {
1233 self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len);1248 self.mod_init_func_section_index = try self.allocateSection(
1234 try data_const_seg.addSection(self.base.allocator, "__mod_init_func", .{1249 self.data_const_segment_cmd_index.?,
1235 .flags = macho.S_MOD_INIT_FUNC_POINTERS,1250 "__mod_init_func",
1236 });1251 sect.size,
1237 needs_allocation = true;1252 sect.@"align",
1253 .{
1254 .flags = macho.S_MOD_INIT_FUNC_POINTERS,
1255 },
1256 );
1238 }1257 }
12391258
1240 break :blk .{1259 break :blk .{
...@@ -1244,11 +1263,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1244,11 +1263,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1244 },1263 },
1245 macho.S_MOD_TERM_FUNC_POINTERS => {1264 macho.S_MOD_TERM_FUNC_POINTERS => {
1246 if (self.mod_term_func_section_index == null) {1265 if (self.mod_term_func_section_index == null) {
1247 self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len);1266 self.mod_term_func_section_index = try self.allocateSection(
1248 try data_const_seg.addSection(self.base.allocator, "__mod_term_func", .{1267 self.data_const_segment_cmd_index.?,
1249 .flags = macho.S_MOD_TERM_FUNC_POINTERS,1268 "__mod_term_func",
1250 });1269 sect.size,
1251 needs_allocation = true;1270 sect.@"align",
1271 .{
1272 .flags = macho.S_MOD_TERM_FUNC_POINTERS,
1273 },
1274 );
1252 }1275 }
12531276
1254 break :blk .{1277 break :blk .{
...@@ -1258,11 +1281,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1258,11 +1281,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1258 },1281 },
1259 macho.S_ZEROFILL => {1282 macho.S_ZEROFILL => {
1260 if (self.bss_section_index == null) {1283 if (self.bss_section_index == null) {
1261 self.bss_section_index = @intCast(u16, data_seg.sections.items.len);1284 self.bss_section_index = try self.allocateSection(
1262 try data_seg.addSection(self.base.allocator, "__bss", .{1285 self.data_segment_cmd_index.?,
1263 .flags = macho.S_ZEROFILL,1286 "__bss",
1264 });1287 sect.size,
1265 needs_allocation = true;1288 sect.@"align",
1289 .{
1290 .flags = macho.S_ZEROFILL,
1291 },
1292 );
1266 }1293 }
12671294
1268 break :blk .{1295 break :blk .{
...@@ -1272,11 +1299,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1272,11 +1299,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1272 },1299 },
1273 macho.S_THREAD_LOCAL_VARIABLES => {1300 macho.S_THREAD_LOCAL_VARIABLES => {
1274 if (self.tlv_section_index == null) {1301 if (self.tlv_section_index == null) {
1275 self.tlv_section_index = @intCast(u16, data_seg.sections.items.len);1302 self.tlv_section_index = try self.allocateSection(
1276 try data_seg.addSection(self.base.allocator, "__thread_vars", .{1303 self.data_segment_cmd_index.?,
1277 .flags = macho.S_THREAD_LOCAL_VARIABLES,1304 "__thread_vars",
1278 });1305 sect.size,
1279 needs_allocation = true;1306 sect.@"align",
1307 .{
1308 .flags = macho.S_THREAD_LOCAL_VARIABLES,
1309 },
1310 );
1280 }1311 }
12811312
1282 break :blk .{1313 break :blk .{
...@@ -1286,11 +1317,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1286,11 +1317,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1286 },1317 },
1287 macho.S_THREAD_LOCAL_REGULAR => {1318 macho.S_THREAD_LOCAL_REGULAR => {
1288 if (self.tlv_data_section_index == null) {1319 if (self.tlv_data_section_index == null) {
1289 self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len);1320 self.tlv_data_section_index = try self.allocateSection(
1290 try data_seg.addSection(self.base.allocator, "__thread_data", .{1321 self.data_segment_cmd_index.?,
1291 .flags = macho.S_THREAD_LOCAL_REGULAR,1322 "__thread_data",
1292 });1323 sect.size,
1293 needs_allocation = true;1324 sect.@"align",
1325 .{
1326 .flags = macho.S_THREAD_LOCAL_REGULAR,
1327 },
1328 );
1294 }1329 }
12951330
1296 break :blk .{1331 break :blk .{
...@@ -1300,11 +1335,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1300,11 +1335,15 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1300 },1335 },
1301 macho.S_THREAD_LOCAL_ZEROFILL => {1336 macho.S_THREAD_LOCAL_ZEROFILL => {
1302 if (self.tlv_bss_section_index == null) {1337 if (self.tlv_bss_section_index == null) {
1303 self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len);1338 self.tlv_bss_section_index = try self.allocateSection(
1304 try data_seg.addSection(self.base.allocator, "__thread_bss", .{1339 self.data_segment_cmd_index.?,
1305 .flags = macho.S_THREAD_LOCAL_ZEROFILL,1340 "__thread_bss",
1306 });1341 sect.size,
1307 needs_allocation = true;1342 sect.@"align",
1343 .{
1344 .flags = macho.S_THREAD_LOCAL_ZEROFILL,
1345 },
1346 );
1308 }1347 }
13091348
1310 break :blk .{1349 break :blk .{
...@@ -1317,9 +1356,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1317,9 +1356,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1317 // TODO I believe __eh_frame is currently part of __unwind_info section1356 // TODO I believe __eh_frame is currently part of __unwind_info section
1318 // in the latest ld64 output.1357 // in the latest ld64 output.
1319 if (self.eh_frame_section_index == null) {1358 if (self.eh_frame_section_index == null) {
1320 self.eh_frame_section_index = @intCast(u16, text_seg.sections.items.len);1359 self.eh_frame_section_index = try self.allocateSection(
1321 try text_seg.addSection(self.base.allocator, "__eh_frame", .{});1360 self.text_segment_cmd_index.?,
1322 needs_allocation = true;1361 "__eh_frame",
1362 sect.size,
1363 sect.@"align",
1364 .{},
1365 );
1323 }1366 }
13241367
1325 break :blk .{1368 break :blk .{
...@@ -1330,9 +1373,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1330,9 +1373,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13301373
1331 // TODO audit this: is this the right mapping?1374 // TODO audit this: is this the right mapping?
1332 if (self.data_const_section_index == null) {1375 if (self.data_const_section_index == null) {
1333 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);1376 self.data_const_section_index = try self.allocateSection(
1334 try data_const_seg.addSection(self.base.allocator, "__const", .{});1377 self.data_const_segment_cmd_index.?,
1335 needs_allocation = true;1378 "__const",
1379 sect.size,
1380 sect.@"align",
1381 .{},
1382 );
1336 }1383 }
13371384
1338 break :blk .{1385 break :blk .{
...@@ -1343,11 +1390,17 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1343,11 +1390,17 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1343 macho.S_REGULAR => {1390 macho.S_REGULAR => {
1344 if (commands.sectionIsCode(sect)) {1391 if (commands.sectionIsCode(sect)) {
1345 if (self.text_section_index == null) {1392 if (self.text_section_index == null) {
1346 self.text_section_index = @intCast(u16, text_seg.sections.items.len);1393 self.text_section_index = try self.allocateSection(
1347 try text_seg.addSection(self.base.allocator, "__text", .{1394 self.text_segment_cmd_index.?,
1348 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,1395 "__text",
1349 });1396 sect.size,
1350 needs_allocation = true;1397 sect.@"align",
1398 .{
1399 .flags = macho.S_REGULAR |
1400 macho.S_ATTR_PURE_INSTRUCTIONS |
1401 macho.S_ATTR_SOME_INSTRUCTIONS,
1402 },
1403 );
1351 }1404 }
13521405
1353 break :blk .{1406 break :blk .{
...@@ -1368,9 +1421,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1368,9 +1421,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1368 if (mem.eql(u8, segname, "__TEXT")) {1421 if (mem.eql(u8, segname, "__TEXT")) {
1369 if (mem.eql(u8, sectname, "__ustring")) {1422 if (mem.eql(u8, sectname, "__ustring")) {
1370 if (self.ustring_section_index == null) {1423 if (self.ustring_section_index == null) {
1371 self.ustring_section_index = @intCast(u16, text_seg.sections.items.len);1424 self.ustring_section_index = try self.allocateSection(
1372 try text_seg.addSection(self.base.allocator, "__ustring", .{});1425 self.text_segment_cmd_index.?,
1373 needs_allocation = true;1426 "__ustring",
1427 sect.size,
1428 sect.@"align",
1429 .{},
1430 );
1374 }1431 }
13751432
1376 break :blk .{1433 break :blk .{
...@@ -1379,9 +1436,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1379,9 +1436,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1379 };1436 };
1380 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {1437 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {
1381 if (self.gcc_except_tab_section_index == null) {1438 if (self.gcc_except_tab_section_index == null) {
1382 self.gcc_except_tab_section_index = @intCast(u16, text_seg.sections.items.len);1439 self.gcc_except_tab_section_index = try self.allocateSection(
1383 try text_seg.addSection(self.base.allocator, "__gcc_except_tab", .{});1440 self.text_segment_cmd_index.?,
1384 needs_allocation = true;1441 "__gcc_except_tab",
1442 sect.size,
1443 sect.@"align",
1444 .{},
1445 );
1385 }1446 }
13861447
1387 break :blk .{1448 break :blk .{
...@@ -1390,9 +1451,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1390,9 +1451,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1390 };1451 };
1391 } else if (mem.eql(u8, sectname, "__objc_methlist")) {1452 } else if (mem.eql(u8, sectname, "__objc_methlist")) {
1392 if (self.objc_methlist_section_index == null) {1453 if (self.objc_methlist_section_index == null) {
1393 self.objc_methlist_section_index = @intCast(u16, text_seg.sections.items.len);1454 self.objc_methlist_section_index = try self.allocateSection(
1394 try text_seg.addSection(self.base.allocator, "__objc_methlist", .{});1455 self.text_segment_cmd_index.?,
1395 needs_allocation = true;1456 "__objc_methlist",
1457 sect.size,
1458 sect.@"align",
1459 .{},
1460 );
1396 }1461 }
13971462
1398 break :blk .{1463 break :blk .{
...@@ -1406,9 +1471,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1406,9 +1471,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1406 mem.eql(u8, sectname, "__gopclntab"))1471 mem.eql(u8, sectname, "__gopclntab"))
1407 {1472 {
1408 if (self.data_const_section_index == null) {1473 if (self.data_const_section_index == null) {
1409 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);1474 self.data_const_section_index = try self.allocateSection(
1410 try data_const_seg.addSection(self.base.allocator, "__const", .{});1475 self.data_const_segment_cmd_index.?,
1411 needs_allocation = true;1476 "__const",
1477 sect.size,
1478 sect.@"align",
1479 .{},
1480 );
1412 }1481 }
14131482
1414 break :blk .{1483 break :blk .{
...@@ -1417,9 +1486,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1417,9 +1486,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1417 };1486 };
1418 } else {1487 } else {
1419 if (self.text_const_section_index == null) {1488 if (self.text_const_section_index == null) {
1420 self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);1489 self.text_const_section_index = try self.allocateSection(
1421 try text_seg.addSection(self.base.allocator, "__const", .{});1490 self.text_segment_cmd_index.?,
1422 needs_allocation = true;1491 "__const",
1492 sect.size,
1493 sect.@"align",
1494 .{},
1495 );
1423 }1496 }
14241497
1425 break :blk .{1498 break :blk .{
...@@ -1431,9 +1504,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1431,9 +1504,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14311504
1432 if (mem.eql(u8, segname, "__DATA_CONST")) {1505 if (mem.eql(u8, segname, "__DATA_CONST")) {
1433 if (self.data_const_section_index == null) {1506 if (self.data_const_section_index == null) {
1434 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);1507 self.data_const_section_index = try self.allocateSection(
1435 try data_const_seg.addSection(self.base.allocator, "__const", .{});1508 self.data_const_segment_cmd_index.?,
1436 needs_allocation = true;1509 "__const",
1510 sect.size,
1511 sect.@"align",
1512 .{},
1513 );
1437 }1514 }
14381515
1439 break :blk .{1516 break :blk .{
...@@ -1445,9 +1522,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1445,9 +1522,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1445 if (mem.eql(u8, segname, "__DATA")) {1522 if (mem.eql(u8, segname, "__DATA")) {
1446 if (mem.eql(u8, sectname, "__const")) {1523 if (mem.eql(u8, sectname, "__const")) {
1447 if (self.data_const_section_index == null) {1524 if (self.data_const_section_index == null) {
1448 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);1525 self.data_const_section_index = try self.allocateSection(
1449 try data_const_seg.addSection(self.base.allocator, "__const", .{});1526 self.data_const_segment_cmd_index.?,
1450 needs_allocation = true;1527 "__const",
1528 sect.size,
1529 sect.@"align",
1530 .{},
1531 );
1451 }1532 }
14521533
1453 break :blk .{1534 break :blk .{
...@@ -1456,9 +1537,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1456,9 +1537,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1456 };1537 };
1457 } else if (mem.eql(u8, sectname, "__cfstring")) {1538 } else if (mem.eql(u8, sectname, "__cfstring")) {
1458 if (self.objc_cfstring_section_index == null) {1539 if (self.objc_cfstring_section_index == null) {
1459 self.objc_cfstring_section_index = @intCast(u16, data_const_seg.sections.items.len);1540 self.objc_cfstring_section_index = try self.allocateSection(
1460 try data_const_seg.addSection(self.base.allocator, "__cfstring", .{});1541 self.data_const_segment_cmd_index.?,
1461 needs_allocation = true;1542 "__cfstring",
1543 sect.size,
1544 sect.@"align",
1545 .{},
1546 );
1462 }1547 }
14631548
1464 break :blk .{1549 break :blk .{
...@@ -1467,9 +1552,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1467,9 +1552,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1467 };1552 };
1468 } else if (mem.eql(u8, sectname, "__objc_classlist")) {1553 } else if (mem.eql(u8, sectname, "__objc_classlist")) {
1469 if (self.objc_classlist_section_index == null) {1554 if (self.objc_classlist_section_index == null) {
1470 self.objc_classlist_section_index = @intCast(u16, data_const_seg.sections.items.len);1555 self.objc_classlist_section_index = try self.allocateSection(
1471 try data_const_seg.addSection(self.base.allocator, "__objc_classlist", .{});1556 self.data_const_segment_cmd_index.?,
1472 needs_allocation = true;1557 "__objc_classlist",
1558 sect.size,
1559 sect.@"align",
1560 .{},
1561 );
1473 }1562 }
14741563
1475 break :blk .{1564 break :blk .{
...@@ -1478,9 +1567,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1478,9 +1567,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1478 };1567 };
1479 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {1568 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {
1480 if (self.objc_imageinfo_section_index == null) {1569 if (self.objc_imageinfo_section_index == null) {
1481 self.objc_imageinfo_section_index = @intCast(u16, data_const_seg.sections.items.len);1570 self.objc_imageinfo_section_index = try self.allocateSection(
1482 try data_const_seg.addSection(self.base.allocator, "__objc_imageinfo", .{});1571 self.data_const_segment_cmd_index.?,
1483 needs_allocation = true;1572 "__objc_imageinfo",
1573 sect.size,
1574 sect.@"align",
1575 .{},
1576 );
1484 }1577 }
14851578
1486 break :blk .{1579 break :blk .{
...@@ -1489,9 +1582,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1489,9 +1582,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1489 };1582 };
1490 } else if (mem.eql(u8, sectname, "__objc_const")) {1583 } else if (mem.eql(u8, sectname, "__objc_const")) {
1491 if (self.objc_const_section_index == null) {1584 if (self.objc_const_section_index == null) {
1492 self.objc_const_section_index = @intCast(u16, data_seg.sections.items.len);1585 self.objc_const_section_index = try self.allocateSection(
1493 try data_seg.addSection(self.base.allocator, "__objc_const", .{});1586 self.data_segment_cmd_index.?,
1494 needs_allocation = true;1587 "__objc_const",
1588 sect.size,
1589 sect.@"align",
1590 .{},
1591 );
1495 }1592 }
14961593
1497 break :blk .{1594 break :blk .{
...@@ -1500,9 +1597,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1500,9 +1597,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1500 };1597 };
1501 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {1598 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {
1502 if (self.objc_classrefs_section_index == null) {1599 if (self.objc_classrefs_section_index == null) {
1503 self.objc_classrefs_section_index = @intCast(u16, data_seg.sections.items.len);1600 self.objc_classrefs_section_index = try self.allocateSection(
1504 try data_seg.addSection(self.base.allocator, "__objc_classrefs", .{});1601 self.data_segment_cmd_index.?,
1505 needs_allocation = true;1602 "__objc_classrefs",
1603 sect.size,
1604 sect.@"align",
1605 .{},
1606 );
1506 }1607 }
15071608
1508 break :blk .{1609 break :blk .{
...@@ -1511,9 +1612,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1511,9 +1612,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1511 };1612 };
1512 } else if (mem.eql(u8, sectname, "__objc_data")) {1613 } else if (mem.eql(u8, sectname, "__objc_data")) {
1513 if (self.objc_data_section_index == null) {1614 if (self.objc_data_section_index == null) {
1514 self.objc_data_section_index = @intCast(u16, data_seg.sections.items.len);1615 self.objc_data_section_index = try self.allocateSection(
1515 try data_seg.addSection(self.base.allocator, "__objc_data", .{});1616 self.data_segment_cmd_index.?,
1516 needs_allocation = true;1617 "__objc_data",
1618 sect.size,
1619 sect.@"align",
1620 .{},
1621 );
1517 }1622 }
15181623
1519 break :blk .{1624 break :blk .{
...@@ -1522,9 +1627,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1522,9 +1627,13 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1522 };1627 };
1523 } else {1628 } else {
1524 if (self.data_section_index == null) {1629 if (self.data_section_index == null) {
1525 self.data_section_index = @intCast(u16, data_seg.sections.items.len);1630 self.data_section_index = try self.allocateSection(
1526 try data_seg.addSection(self.base.allocator, "__data", .{});1631 self.data_segment_cmd_index.?,
1527 needs_allocation = true;1632 "__data",
1633 sect.size,
1634 sect.@"align",
1635 .{},
1636 );
1528 }1637 }
15291638
1530 break :blk .{1639 break :blk .{
...@@ -1545,42 +1654,6 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1545,42 +1654,6 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1545 else => break :blk null,1654 else => break :blk null,
1546 }1655 }
1547 };1656 };
1548
1549 if (res) |match| {
1550 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
1551 _ = try self.block_free_lists.getOrPutValue(self.base.allocator, match, .{});
1552
1553 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
1554 if (!use_stage1) {
1555 const target_seg = &self.load_commands.items[match.seg].Segment;
1556 const target_sect = &target_seg.sections.items[match.sect];
1557
1558 // Update section's alignment
1559 // TODO if sect.@"align" > target_sect.@"align", should we move the entire
1560 // section to match the required alignment?
1561 target_sect.@"align" = math.max(target_sect.@"align", sect.@"align");
1562
1563 if (needs_allocation) {
1564 const alignment = try math.powi(u32, 2, target_sect.@"align");
1565 const needed_size = sect.size;
1566 const off = target_seg.findFreeSpace(needed_size, alignment, self.header_pad);
1567 assert(off + needed_size <= target_seg.inner.fileoff + target_seg.inner.filesize); // TODO expand
1568
1569 log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{
1570 segname,
1571 sectname,
1572 off,
1573 off + needed_size,
1574 });
1575
1576 target_sect.addr = target_seg.inner.vmaddr + off;
1577 target_sect.size = needed_size;
1578 target_sect.offset = @intCast(u32, off);
1579 self.load_commands_dirty = true;
1580 }
1581 }
1582 }
1583
1584 return res;1657 return res;
1585}1658}
15861659
...@@ -3878,9 +3951,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3878,9 +3951,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3878 if (self.pagezero_segment_cmd_index == null) {3951 if (self.pagezero_segment_cmd_index == null) {
3879 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);3952 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3880 try self.load_commands.append(self.base.allocator, .{3953 try self.load_commands.append(self.base.allocator, .{
3881 .Segment = SegmentCommand.empty("__PAGEZERO", .{3954 .Segment = .{
3882 .vmsize = 0x100000000, // size always set to 4GB3955 .inner = .{
3883 }),3956 .segname = makeStaticString("__PAGEZERO"),
3957 .vmsize = 0x100000000, // size always set to 4GB
3958 },
3959 },
3884 });3960 });
3885 self.load_commands_dirty = true;3961 self.load_commands_dirty = true;
3886 }3962 }
...@@ -3895,51 +3971,39 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3895,51 +3971,39 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3895 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });3971 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
38963972
3897 try self.load_commands.append(self.base.allocator, .{3973 try self.load_commands.append(self.base.allocator, .{
3898 .Segment = SegmentCommand.empty("__TEXT", .{3974 .Segment = .{
3899 .vmaddr = 0x100000000, // always starts at 4GB3975 .inner = .{
3900 .vmsize = needed_size,3976 .segname = makeStaticString("__TEXT"),
3901 .filesize = needed_size,3977 .vmaddr = 0x100000000, // always starts at 4GB
3902 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,3978 .vmsize = needed_size,
3903 .initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,3979 .filesize = needed_size,
3904 }),3980 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
3981 .initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
3982 },
3983 },
3905 });3984 });
3906 self.load_commands_dirty = true;3985 self.load_commands_dirty = true;
3907 }3986 }
39083987
3909 if (self.text_section_index == null) {3988 if (self.text_section_index == null) {
3910 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
3911 self.text_section_index = @intCast(u16, text_segment.sections.items.len);
3912
3913 const alignment: u2 = switch (self.base.options.target.cpu.arch) {3989 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3914 .x86_64 => 0,3990 .x86_64 => 0,
3915 .aarch64 => 2,3991 .aarch64 => 2,
3916 else => unreachable, // unhandled architecture type3992 else => unreachable, // unhandled architecture type
3917 };3993 };
3918 const needed_size = self.base.options.program_code_size_hint;3994 const needed_size = self.base.options.program_code_size_hint;
3919 const off = text_segment.findFreeSpace(needed_size, @as(u16, 1) << alignment, self.header_pad);3995 self.text_section_index = try self.allocateSection(
39203996 self.text_segment_cmd_index.?,
3921 log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size });3997 "__text",
39223998 needed_size,
3923 try text_segment.addSection(self.base.allocator, "__text", .{3999 alignment,
3924 .addr = text_segment.inner.vmaddr + off,4000 .{
3925 .size = @intCast(u32, needed_size),4001 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
3926 .offset = @intCast(u32, off),4002 },
3927 .@"align" = alignment,4003 );
3928 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
3929 });
3930 const match = MatchingSection{
3931 .seg = self.text_segment_cmd_index.?,
3932 .sect = self.text_section_index.?,
3933 };
3934 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
3935 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
3936 self.load_commands_dirty = true;
3937 }4004 }
39384005
3939 if (self.stubs_section_index == null) {4006 if (self.stubs_section_index == null) {
3940 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
3941 self.stubs_section_index = @intCast(u16, text_segment.sections.items.len);
3942
3943 const alignment: u2 = switch (self.base.options.target.cpu.arch) {4007 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3944 .x86_64 => 0,4008 .x86_64 => 0,
3945 .aarch64 => 2,4009 .aarch64 => 2,
...@@ -3951,32 +4015,19 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3951,32 +4015,19 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3951 else => unreachable, // unhandled architecture type4015 else => unreachable, // unhandled architecture type
3952 };4016 };
3953 const needed_size = stub_size * self.base.options.symbol_count_hint;4017 const needed_size = stub_size * self.base.options.symbol_count_hint;
3954 const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad);4018 self.stubs_section_index = try self.allocateSection(
3955 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.4019 self.text_segment_cmd_index.?,
39564020 "__stubs",
3957 log.debug("found __stubs section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4021 needed_size,
39584022 alignment,
3959 try text_segment.addSection(self.base.allocator, "__stubs", .{4023 .{
3960 .addr = text_segment.inner.vmaddr + off,4024 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
3961 .size = needed_size,4025 .reserved2 = stub_size,
3962 .offset = @intCast(u32, off),4026 },
3963 .@"align" = alignment,4027 );
3964 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
3965 .reserved2 = stub_size,
3966 });
3967 const match = MatchingSection{
3968 .seg = self.text_segment_cmd_index.?,
3969 .sect = self.stubs_section_index.?,
3970 };
3971 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
3972 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
3973 self.load_commands_dirty = true;
3974 }4028 }
39754029
3976 if (self.stub_helper_section_index == null) {4030 if (self.stub_helper_section_index == null) {
3977 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
3978 self.stub_helper_section_index = @intCast(u16, text_segment.sections.items.len);
3979
3980 const alignment: u2 = switch (self.base.options.target.cpu.arch) {4031 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3981 .x86_64 => 0,4032 .x86_64 => 0,
3982 .aarch64 => 2,4033 .aarch64 => 2,
...@@ -3993,25 +4044,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3993,25 +4044,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3993 else => unreachable,4044 else => unreachable,
3994 };4045 };
3995 const needed_size = stub_size * self.base.options.symbol_count_hint + preamble_size;4046 const needed_size = stub_size * self.base.options.symbol_count_hint + preamble_size;
3996 const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad);4047 self.stub_helper_section_index = try self.allocateSection(
3997 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.4048 self.text_segment_cmd_index.?,
39984049 "__stub_helper",
3999 log.debug("found __stub_helper section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4050 needed_size,
40004051 alignment,
4001 try text_segment.addSection(self.base.allocator, "__stub_helper", .{4052 .{
4002 .addr = text_segment.inner.vmaddr + off,4053 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
4003 .size = needed_size,4054 },
4004 .offset = @intCast(u32, off),4055 );
4005 .@"align" = alignment,
4006 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
4007 });
4008 const match = MatchingSection{
4009 .seg = self.text_segment_cmd_index.?,
4010 .sect = self.stub_helper_section_index.?,
4011 };
4012 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4013 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4014 self.load_commands_dirty = true;
4015 }4056 }
40164057
4017 if (self.data_const_segment_cmd_index == null) {4058 if (self.data_const_segment_cmd_index == null) {
...@@ -4020,45 +4061,39 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -4020,45 +4061,39 @@ pub fn populateMissingMetadata(self: *MachO) !void {
4020 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;4061 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4021 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);4062 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
40224063
4023 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });4064 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
4065 address_and_offset.offset,
4066 address_and_offset.offset + needed_size,
4067 });
40244068
4025 try self.load_commands.append(self.base.allocator, .{4069 try self.load_commands.append(self.base.allocator, .{
4026 .Segment = SegmentCommand.empty("__DATA_CONST", .{4070 .Segment = .{
4027 .vmaddr = address_and_offset.address,4071 .inner = .{
4028 .vmsize = needed_size,4072 .segname = makeStaticString("__DATA_CONST"),
4029 .fileoff = address_and_offset.offset,4073 .vmaddr = address_and_offset.address,
4030 .filesize = needed_size,4074 .vmsize = needed_size,
4031 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,4075 .fileoff = address_and_offset.offset,
4032 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,4076 .filesize = needed_size,
4033 }),4077 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
4078 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
4079 },
4080 },
4034 });4081 });
4035 self.load_commands_dirty = true;4082 self.load_commands_dirty = true;
4036 }4083 }
40374084
4038 if (self.got_section_index == null) {4085 if (self.got_section_index == null) {
4039 const dc_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4040 self.got_section_index = @intCast(u16, dc_segment.sections.items.len);
4041
4042 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;4086 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4043 const off = dc_segment.findFreeSpace(needed_size, @alignOf(u64), null);4087 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4044 assert(off + needed_size <= dc_segment.inner.fileoff + dc_segment.inner.filesize); // TODO Must expand __DATA_CONST segment.4088 self.got_section_index = try self.allocateSection(
40454089 self.data_const_segment_cmd_index.?,
4046 log.debug("found __got section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4090 "__got",
40474091 needed_size,
4048 try dc_segment.addSection(self.base.allocator, "__got", .{4092 alignment,
4049 .addr = dc_segment.inner.vmaddr + off - dc_segment.inner.fileoff,4093 .{
4050 .size = needed_size,4094 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
4051 .offset = @intCast(u32, off),4095 },
4052 .@"align" = 3, // 2^3 = @sizeOf(u64)4096 );
4053 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
4054 });
4055 const match = MatchingSection{
4056 .seg = self.data_const_segment_cmd_index.?,
4057 .sect = self.got_section_index.?,
4058 };
4059 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4060 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4061 self.load_commands_dirty = true;
4062 }4097 }
40634098
4064 if (self.data_segment_cmd_index == null) {4099 if (self.data_segment_cmd_index == null) {
...@@ -4070,175 +4105,115 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -4070,175 +4105,115 @@ pub fn populateMissingMetadata(self: *MachO) !void {
4070 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });4105 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
40714106
4072 try self.load_commands.append(self.base.allocator, .{4107 try self.load_commands.append(self.base.allocator, .{
4073 .Segment = SegmentCommand.empty("__DATA", .{4108 .Segment = .{
4074 .vmaddr = address_and_offset.address,4109 .inner = .{
4075 .vmsize = needed_size,4110 .segname = makeStaticString("__DATA"),
4076 .fileoff = address_and_offset.offset,4111 .vmaddr = address_and_offset.address,
4077 .filesize = needed_size,4112 .vmsize = needed_size,
4078 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,4113 .fileoff = address_and_offset.offset,
4079 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,4114 .filesize = needed_size,
4080 }),4115 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
4116 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
4117 },
4118 },
4081 });4119 });
4082 self.load_commands_dirty = true;4120 self.load_commands_dirty = true;
4083 }4121 }
40844122
4085 if (self.la_symbol_ptr_section_index == null) {4123 if (self.la_symbol_ptr_section_index == null) {
4086 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4087 self.la_symbol_ptr_section_index = @intCast(u16, data_segment.sections.items.len);
4088
4089 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;4124 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4090 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);4125 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4091 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.4126 self.la_symbol_ptr_section_index = try self.allocateSection(
40924127 self.data_segment_cmd_index.?,
4093 log.debug("found __la_symbol_ptr section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4128 "__la_symbol_ptr",
40944129 needed_size,
4095 try data_segment.addSection(self.base.allocator, "__la_symbol_ptr", .{4130 alignment,
4096 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,4131 .{
4097 .size = needed_size,4132 .flags = macho.S_LAZY_SYMBOL_POINTERS,
4098 .offset = @intCast(u32, off),4133 },
4099 .@"align" = 3, // 2^3 = @sizeOf(u64)4134 );
4100 .flags = macho.S_LAZY_SYMBOL_POINTERS,
4101 });
4102 const match = MatchingSection{
4103 .seg = self.data_segment_cmd_index.?,
4104 .sect = self.la_symbol_ptr_section_index.?,
4105 };
4106 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4107 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4108 self.load_commands_dirty = true;
4109 }4135 }
41104136
4111 if (self.data_section_index == null) {4137 if (self.data_section_index == null) {
4112 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4113 self.data_section_index = @intCast(u16, data_segment.sections.items.len);
4114
4115 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;4138 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4116 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);4139 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4117 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.4140 self.data_section_index = try self.allocateSection(
41184141 self.data_segment_cmd_index.?,
4119 log.debug("found __data section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4142 "__data",
41204143 needed_size,
4121 try data_segment.addSection(self.base.allocator, "__data", .{4144 alignment,
4122 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,4145 .{},
4123 .size = needed_size,4146 );
4124 .offset = @intCast(u32, off),
4125 .@"align" = 3, // 2^3 = @sizeOf(u64)
4126 });
4127 const match = MatchingSection{
4128 .seg = self.data_segment_cmd_index.?,
4129 .sect = self.data_section_index.?,
4130 };
4131 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4132 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4133 self.load_commands_dirty = true;
4134 }4147 }
41354148
4136 if (self.tlv_section_index == null) {4149 if (self.tlv_section_index == null) {
4137 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4138 self.tlv_section_index = @intCast(u16, data_segment.sections.items.len);
4139
4140 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;4150 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4141 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);4151 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4142 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.4152 self.tlv_section_index = try self.allocateSection(
41434153 self.data_segment_cmd_index.?,
4144 log.debug("found __thread_vars section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4154 "__thread_vars",
41454155 needed_size,
4146 try data_segment.addSection(self.base.allocator, "__thread_vars", .{4156 alignment,
4147 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,4157 .{
4148 .size = needed_size,4158 .flags = macho.S_THREAD_LOCAL_VARIABLES,
4149 .offset = @intCast(u32, off),4159 },
4150 .@"align" = 3, // 2^3 = @sizeOf(u64)4160 );
4151 .flags = macho.S_THREAD_LOCAL_VARIABLES,
4152 });
4153 const match = MatchingSection{
4154 .seg = self.data_segment_cmd_index.?,
4155 .sect = self.tlv_section_index.?,
4156 };
4157 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4158 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4159 self.load_commands_dirty = true;
4160 }4161 }
41614162
4162 if (self.tlv_data_section_index == null) {4163 if (self.tlv_data_section_index == null) {
4163 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4164 self.tlv_data_section_index = @intCast(u16, data_segment.sections.items.len);
4165
4166 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;4164 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4167 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);4165 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4168 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.4166 self.tlv_data_section_index = try self.allocateSection(
41694167 self.data_segment_cmd_index.?,
4170 log.debug("found __thread_data section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4168 "__thread_data",
41714169 needed_size,
4172 try data_segment.addSection(self.base.allocator, "__thread_data", .{4170 alignment,
4173 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,4171 .{
4174 .size = needed_size,4172 .flags = macho.S_THREAD_LOCAL_REGULAR,
4175 .offset = @intCast(u32, off),4173 },
4176 .@"align" = 3, // 2^3 = @sizeOf(u64)4174 );
4177 .flags = macho.S_THREAD_LOCAL_REGULAR,
4178 });
4179 const match = MatchingSection{
4180 .seg = self.data_segment_cmd_index.?,
4181 .sect = self.tlv_data_section_index.?,
4182 };
4183 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4184 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4185 self.load_commands_dirty = true;
4186 }4175 }
41874176
4188 if (self.tlv_bss_section_index == null) {4177 if (self.tlv_bss_section_index == null) {
4189 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4190 self.tlv_bss_section_index = @intCast(u16, data_segment.sections.items.len);
4191
4192 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;4178 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4193 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);4179 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4194 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.4180 self.tlv_bss_section_index = try self.allocateSection(
41954181 self.data_segment_cmd_index.?,
4196 log.debug("found __thread_bss section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4182 "__thread_bss",
4183 needed_size,
4184 alignment,
4185 .{
4186 .flags = macho.S_THREAD_LOCAL_ZEROFILL,
4187 },
4188 );
41974189
4198 // We keep offset to the section in a separate variable as the actual section is usually pointing at the4190 // We keep offset to the section in a separate variable as the actual section is usually pointing at the
4199 // beginning of the file.4191 // beginning of the file.
4200 self.tlv_bss_file_offset = off;4192 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4201 try data_segment.addSection(self.base.allocator, "__thread_bss", .{4193 const out_sect = &seg.sections.items[self.tlv_bss_section_index.?];
4202 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,4194 self.tlv_bss_file_offset = out_sect.offset;
4203 .size = needed_size,4195 out_sect.offset = 0;
4204 .@"align" = 3, // 2^3 = @sizeOf(u64)
4205 .flags = macho.S_THREAD_LOCAL_ZEROFILL,
4206 });
4207 const match = MatchingSection{
4208 .seg = self.data_segment_cmd_index.?,
4209 .sect = self.tlv_bss_section_index.?,
4210 };
4211 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4212 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4213 self.load_commands_dirty = true;
4214 }4196 }
42154197
4216 if (self.bss_section_index == null) {4198 if (self.bss_section_index == null) {
4217 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4218 self.bss_section_index = @intCast(u16, data_segment.sections.items.len);
4219
4220 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;4199 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4221 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);4200 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4222 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.4201 self.bss_section_index = try self.allocateSection(
42234202 self.data_segment_cmd_index.?,
4224 log.debug("found __bss section free space 0x{x} to 0x{x}", .{ off, off + needed_size });4203 "__bss",
4204 needed_size,
4205 alignment,
4206 .{
4207 .flags = macho.S_ZEROFILL,
4208 },
4209 );
42254210
4226 // We keep offset to the section in a separate variable as the actual section is usually pointing at the4211 // We keep offset to the section in a separate variable as the actual section is usually pointing at the
4227 // beginning of the file.4212 // beginning of the file.
4228 self.bss_file_offset = off;4213 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4229 try data_segment.addSection(self.base.allocator, "__bss", .{4214 const out_sect = &seg.sections.items[self.bss_section_index.?];
4230 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,4215 self.bss_file_offset = out_sect.offset;
4231 .size = 0,4216 out_sect.offset = 0;
4232 .@"align" = 3, // 2^3 = @sizeOf(u64)
4233 .flags = macho.S_ZEROFILL,
4234 });
4235 const match = MatchingSection{
4236 .seg = self.data_segment_cmd_index.?,
4237 .sect = self.bss_section_index.?,
4238 };
4239 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4240 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4241 self.load_commands_dirty = true;
4242 }4217 }
42434218
4244 if (self.linkedit_segment_cmd_index == null) {4219 if (self.linkedit_segment_cmd_index == null) {
...@@ -4248,12 +4223,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -4248,12 +4223,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {
4248 log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});4223 log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});
42494224
4250 try self.load_commands.append(self.base.allocator, .{4225 try self.load_commands.append(self.base.allocator, .{
4251 .Segment = SegmentCommand.empty("__LINKEDIT", .{4226 .Segment = .{
4252 .vmaddr = address_and_offset.address,4227 .inner = .{
4253 .fileoff = address_and_offset.offset,4228 .segname = makeStaticString("__LINKEDIT"),
4254 .maxprot = macho.VM_PROT_READ,4229 .vmaddr = address_and_offset.address,
4255 .initprot = macho.VM_PROT_READ,4230 .fileoff = address_and_offset.offset,
4256 }),4231 .maxprot = macho.VM_PROT_READ,
4232 .initprot = macho.VM_PROT_READ,
4233 },
4234 },
4257 });4235 });
4258 self.load_commands_dirty = true;4236 self.load_commands_dirty = true;
4259 }4237 }
...@@ -4485,6 +4463,67 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -4485,6 +4463,67 @@ pub fn populateMissingMetadata(self: *MachO) !void {
4485 }4463 }
4486}4464}
44874465
4466const AllocateSectionOpts = struct {
4467 flags: u32 = macho.S_REGULAR,
4468 reserved1: u32 = 0,
4469 reserved2: u32 = 0,
4470};
4471
4472fn allocateSection(
4473 self: *MachO,
4474 segment_id: u16,
4475 sectname: []const u8,
4476 size: u64,
4477 alignment: u32,
4478 opts: AllocateSectionOpts,
4479) !u16 {
4480 const seg = &self.load_commands.items[segment_id].Segment;
4481 var sect = macho.section_64{
4482 .sectname = makeStaticString(sectname),
4483 .segname = seg.inner.segname,
4484 .size = @intCast(u32, size),
4485 .@"align" = alignment,
4486 .flags = opts.flags,
4487 .reserved1 = opts.reserved1,
4488 .reserved2 = opts.reserved2,
4489 };
4490
4491 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
4492 if (!use_stage1) {
4493 const alignment_pow_2 = try math.powi(u32, 2, alignment);
4494 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;
4495 const off = seg.findFreeSpace(size, alignment_pow_2, padding);
4496
4497 assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand
4498
4499 log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{
4500 commands.segmentName(sect),
4501 commands.sectionName(sect),
4502 off,
4503 off + size,
4504 });
4505
4506 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;
4507 sect.offset = @intCast(u32, off);
4508 }
4509
4510 const index = @intCast(u16, seg.sections.items.len);
4511 try seg.sections.append(self.base.allocator, sect);
4512 seg.inner.cmdsize += @sizeOf(macho.section_64);
4513 seg.inner.nsects += 1;
4514
4515 const match = MatchingSection{
4516 .seg = segment_id,
4517 .sect = index,
4518 };
4519 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4520 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
4521
4522 self.load_commands_dirty = true;
4523
4524 return index;
4525}
4526
4488fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {4527fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
4489 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;4528 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4490 const text_section = &text_segment.sections.items[self.text_section_index.?];4529 const text_section = &text_segment.sections.items[self.text_section_index.?];
...@@ -5513,6 +5552,13 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -5513,6 +5552,13 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
5513 std.math.maxInt(@TypeOf(actual_size));5552 std.math.maxInt(@TypeOf(actual_size));
5514}5553}
55155554
5555pub fn makeStaticString(bytes: []const u8) [16]u8 {
5556 var buf = [_]u8{0} ** 16;
5557 assert(bytes.len <= buf.len);
5558 mem.copy(u8, &buf, bytes);
5559 return buf;
5560}
5561
5516pub fn makeString(self: *MachO, string: []const u8) !u32 {5562pub fn makeString(self: *MachO, string: []const u8) !u32 {
5517 if (self.strtab_dir.getAdapted(@as([]const u8, string), StringSliceAdapter{ .strtab = &self.strtab })) |off| {5563 if (self.strtab_dir.getAdapted(@as([]const u8, string), StringSliceAdapter{ .strtab = &self.strtab })) |off| {
5518 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });5564 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
src/link/MachO/DebugSymbols.zig+77-92
...@@ -5,23 +5,26 @@ const assert = std.debug.assert;...@@ -5,23 +5,26 @@ const assert = std.debug.assert;
5const fs = std.fs;5const fs = std.fs;
6const log = std.log.scoped(.dsym);6const log = std.log.scoped(.dsym);
7const macho = std.macho;7const macho = std.macho;
8const math = std.math;
8const mem = std.mem;9const mem = std.mem;
9const DW = std.dwarf;10const DW = std.dwarf;
10const leb = std.leb;11const leb = std.leb;
11const Allocator = mem.Allocator;12const Allocator = mem.Allocator;
1213
13const build_options = @import("build_options");14const build_options = @import("build_options");
15const commands = @import("commands.zig");
14const trace = @import("../../tracy.zig").trace;16const trace = @import("../../tracy.zig").trace;
17const LoadCommand = commands.LoadCommand;
15const Module = @import("../../Module.zig");18const Module = @import("../../Module.zig");
16const Type = @import("../../type.zig").Type;19const Type = @import("../../type.zig").Type;
17const link = @import("../../link.zig");20const link = @import("../../link.zig");
18const MachO = @import("../MachO.zig");21const MachO = @import("../MachO.zig");
19const SrcFn = MachO.SrcFn;
20const TextBlock = MachO.TextBlock;22const TextBlock = MachO.TextBlock;
23const SegmentCommand = commands.SegmentCommand;
24const SrcFn = MachO.SrcFn;
25const makeStaticString = MachO.makeStaticString;
21const padToIdeal = MachO.padToIdeal;26const padToIdeal = MachO.padToIdeal;
2227
23usingnamespace @import("commands.zig");
24
25const page_size: u16 = 0x1000;28const page_size: u16 = 0x1000;
2629
27base: *MachO,30base: *MachO,
...@@ -185,105 +188,84 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void...@@ -185,105 +188,84 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
185 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });188 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });
186189
187 try self.load_commands.append(allocator, .{190 try self.load_commands.append(allocator, .{
188 .Segment = SegmentCommand.empty("__DWARF", .{191 .Segment = .{
189 .vmaddr = vmaddr,192 .inner = .{
190 .vmsize = needed_size,193 .segname = makeStaticString("__DWARF"),
191 .fileoff = off,194 .vmaddr = vmaddr,
192 .filesize = needed_size,195 .vmsize = needed_size,
193 }),196 .fileoff = off,
197 .filesize = needed_size,
198 },
199 },
194 });200 });
195 self.load_commands_dirty = true;201 self.load_commands_dirty = true;
196 }202 }
197 if (self.debug_str_section_index == null) {203 if (self.debug_str_section_index == null) {
198 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
199 self.debug_str_section_index = @intCast(u16, dwarf_segment.sections.items.len);
200 assert(self.debug_string_table.items.len == 0);204 assert(self.debug_string_table.items.len == 0);
201205 self.debug_str_section_index = try self.allocateSection(
202 try dwarf_segment.addSection(allocator, "__debug_str", .{206 "__debug_str",
203 .addr = dwarf_segment.inner.vmaddr,207 @intCast(u32, self.debug_string_table.items.len),
204 .size = @intCast(u32, self.debug_string_table.items.len),208 0,
205 .offset = @intCast(u32, dwarf_segment.inner.fileoff),209 );
206 .@"align" = 1,
207 });
208 self.load_commands_dirty = true;
209 self.debug_string_table_dirty = true;210 self.debug_string_table_dirty = true;
210 }211 }
211 if (self.debug_info_section_index == null) {212 if (self.debug_info_section_index == null) {
212 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;213 self.debug_info_section_index = try self.allocateSection("__debug_info", 200, 0);
213 self.debug_info_section_index = @intCast(u16, dwarf_segment.sections.items.len);
214
215 const file_size_hint = 200;
216 const p_align = 1;
217 const off = dwarf_segment.findFreeSpace(file_size_hint, p_align, null);
218
219 log.debug("found __debug_info free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
220
221 try dwarf_segment.addSection(allocator, "__debug_info", .{
222 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
223 .size = file_size_hint,
224 .offset = @intCast(u32, off),
225 .@"align" = p_align,
226 });
227 self.load_commands_dirty = true;
228 self.debug_info_header_dirty = true;214 self.debug_info_header_dirty = true;
229 }215 }
230 if (self.debug_abbrev_section_index == null) {216 if (self.debug_abbrev_section_index == null) {
231 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;217 self.debug_abbrev_section_index = try self.allocateSection("__debug_abbrev", 128, 0);
232 self.debug_abbrev_section_index = @intCast(u16, dwarf_segment.sections.items.len);
233
234 const file_size_hint = 128;
235 const p_align = 1;
236 const off = dwarf_segment.findFreeSpace(file_size_hint, p_align, null);
237
238 log.debug("found __debug_abbrev free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
239
240 try dwarf_segment.addSection(allocator, "__debug_abbrev", .{
241 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
242 .size = file_size_hint,
243 .offset = @intCast(u32, off),
244 .@"align" = p_align,
245 });
246 self.load_commands_dirty = true;
247 self.debug_abbrev_section_dirty = true;218 self.debug_abbrev_section_dirty = true;
248 }219 }
249 if (self.debug_aranges_section_index == null) {220 if (self.debug_aranges_section_index == null) {
250 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;221 self.debug_aranges_section_index = try self.allocateSection("__debug_aranges", 160, 4);
251 self.debug_aranges_section_index = @intCast(u16, dwarf_segment.sections.items.len);
252
253 const file_size_hint = 160;
254 const p_align = 16;
255 const off = dwarf_segment.findFreeSpace(file_size_hint, p_align, null);
256
257 log.debug("found __debug_aranges free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
258
259 try dwarf_segment.addSection(allocator, "__debug_aranges", .{
260 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
261 .size = file_size_hint,
262 .offset = @intCast(u32, off),
263 .@"align" = p_align,
264 });
265 self.load_commands_dirty = true;
266 self.debug_aranges_section_dirty = true;222 self.debug_aranges_section_dirty = true;
267 }223 }
268 if (self.debug_line_section_index == null) {224 if (self.debug_line_section_index == null) {
269 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;225 self.debug_line_section_index = try self.allocateSection("__debug_line", 250, 0);
270 self.debug_line_section_index = @intCast(u16, dwarf_segment.sections.items.len);226 self.debug_line_header_dirty = true;
227 }
228}
271229
272 const file_size_hint = 250;230fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u16 {
273 const p_align = 1;231 const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
274 const off = dwarf_segment.findFreeSpace(file_size_hint, p_align, null);232 var sect = macho.section_64{
233 .sectname = makeStaticString(sectname),
234 .segname = seg.inner.segname,
235 .size = @intCast(u32, size),
236 .@"align" = alignment,
237 };
238 const alignment_pow_2 = try math.powi(u32, 2, alignment);
239 const off = seg.findFreeSpace(size, alignment_pow_2, null);
275240
276 log.debug("found __debug_line free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });241 assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand
277242
278 try dwarf_segment.addSection(allocator, "__debug_line", .{243 log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{
279 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,244 commands.segmentName(sect),
280 .size = file_size_hint,245 commands.sectionName(sect),
281 .offset = @intCast(u32, off),246 off,
282 .@"align" = p_align,247 off + size,
283 });248 });
284 self.load_commands_dirty = true;249
285 self.debug_line_header_dirty = true;250 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;
286 }251 sect.offset = @intCast(u32, off);
252
253 const index = @intCast(u16, seg.sections.items.len);
254 try seg.sections.append(self.base.base.allocator, sect);
255 seg.inner.cmdsize += @sizeOf(macho.section_64);
256 seg.inner.nsects += 1;
257
258 // TODO
259 // const match = MatchingSection{
260 // .seg = segment_id,
261 // .sect = index,
262 // };
263 // _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
264 // try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
265
266 self.load_commands_dirty = true;
267
268 return index;
287}269}
288270
289pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Options) !void {271pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Options) !void {
...@@ -611,15 +593,18 @@ pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void {...@@ -611,15 +593,18 @@ pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void {
611}593}
612594
613fn copySegmentCommand(self: *DebugSymbols, allocator: *Allocator, base_cmd: SegmentCommand) !SegmentCommand {595fn copySegmentCommand(self: *DebugSymbols, allocator: *Allocator, base_cmd: SegmentCommand) !SegmentCommand {
614 var cmd = SegmentCommand.empty("", .{596 var cmd = SegmentCommand{
615 .cmdsize = base_cmd.inner.cmdsize,597 .inner = .{
616 .vmaddr = base_cmd.inner.vmaddr,598 .segname = undefined,
617 .vmsize = base_cmd.inner.vmsize,599 .cmdsize = base_cmd.inner.cmdsize,
618 .maxprot = base_cmd.inner.maxprot,600 .vmaddr = base_cmd.inner.vmaddr,
619 .initprot = base_cmd.inner.initprot,601 .vmsize = base_cmd.inner.vmsize,
620 .nsects = base_cmd.inner.nsects,602 .maxprot = base_cmd.inner.maxprot,
621 .flags = base_cmd.inner.flags,603 .initprot = base_cmd.inner.initprot,
622 });604 .nsects = base_cmd.inner.nsects,
605 .flags = base_cmd.inner.flags,
606 },
607 };
623 mem.copy(u8, &cmd.inner.segname, &base_cmd.inner.segname);608 mem.copy(u8, &cmd.inner.segname, &base_cmd.inner.segname);
624609
625 try cmd.sections.ensureCapacity(allocator, cmd.inner.nsects);610 try cmd.sections.ensureCapacity(allocator, cmd.inner.nsects);
...@@ -689,7 +674,7 @@ fn writeLoadCommands(self: *DebugSymbols, allocator: *Allocator) !void {...@@ -689,7 +674,7 @@ fn writeLoadCommands(self: *DebugSymbols, allocator: *Allocator) !void {
689}674}
690675
691fn writeHeader(self: *DebugSymbols) !void {676fn writeHeader(self: *DebugSymbols) !void {
692 var header = emptyHeader(.{677 var header = commands.emptyHeader(.{
693 .filetype = macho.MH_DSYM,678 .filetype = macho.MH_DSYM,
694 });679 });
695680
src/link/MachO/commands.zig+5-88
...@@ -9,6 +9,7 @@ const assert = std.debug.assert;...@@ -9,6 +9,7 @@ const assert = std.debug.assert;
99
10const Allocator = std.mem.Allocator;10const Allocator = std.mem.Allocator;
11const MachO = @import("../MachO.zig");11const MachO = @import("../MachO.zig");
12const makeStaticString = MachO.makeStaticString;
12const padToIdeal = MachO.padToIdeal;13const padToIdeal = MachO.padToIdeal;
1314
14pub const HeaderArgs = struct {15pub const HeaderArgs = struct {
...@@ -217,75 +218,6 @@ pub const SegmentCommand = struct {...@@ -217,75 +218,6 @@ pub const SegmentCommand = struct {
217 inner: macho.segment_command_64,218 inner: macho.segment_command_64,
218 sections: std.ArrayListUnmanaged(macho.section_64) = .{},219 sections: std.ArrayListUnmanaged(macho.section_64) = .{},
219220
220 const SegmentOptions = struct {
221 cmdsize: u32 = @sizeOf(macho.segment_command_64),
222 vmaddr: u64 = 0,
223 vmsize: u64 = 0,
224 fileoff: u64 = 0,
225 filesize: u64 = 0,
226 maxprot: macho.vm_prot_t = macho.VM_PROT_NONE,
227 initprot: macho.vm_prot_t = macho.VM_PROT_NONE,
228 nsects: u32 = 0,
229 flags: u32 = 0,
230 };
231
232 pub fn empty(comptime segname: []const u8, opts: SegmentOptions) SegmentCommand {
233 return .{
234 .inner = .{
235 .cmd = macho.LC_SEGMENT_64,
236 .cmdsize = opts.cmdsize,
237 .segname = makeStaticString(segname),
238 .vmaddr = opts.vmaddr,
239 .vmsize = opts.vmsize,
240 .fileoff = opts.fileoff,
241 .filesize = opts.filesize,
242 .maxprot = opts.maxprot,
243 .initprot = opts.initprot,
244 .nsects = opts.nsects,
245 .flags = opts.flags,
246 },
247 };
248 }
249
250 const SectionOptions = struct {
251 addr: u64 = 0,
252 size: u64 = 0,
253 offset: u32 = 0,
254 @"align": u32 = 0,
255 reloff: u32 = 0,
256 nreloc: u32 = 0,
257 flags: u32 = macho.S_REGULAR,
258 reserved1: u32 = 0,
259 reserved2: u32 = 0,
260 reserved3: u32 = 0,
261 };
262
263 pub fn addSection(
264 self: *SegmentCommand,
265 alloc: *Allocator,
266 comptime sectname: []const u8,
267 opts: SectionOptions,
268 ) !void {
269 var section = macho.section_64{
270 .sectname = makeStaticString(sectname),
271 .segname = undefined,
272 .addr = opts.addr,
273 .size = opts.size,
274 .offset = opts.offset,
275 .@"align" = opts.@"align",
276 .reloff = opts.reloff,
277 .nreloc = opts.nreloc,
278 .flags = opts.flags,
279 .reserved1 = opts.reserved1,
280 .reserved2 = opts.reserved2,
281 .reserved3 = opts.reserved3,
282 };
283 mem.copy(u8, &section.segname, &self.inner.segname);
284 try self.sections.append(alloc, section);
285 self.inner.cmdsize += @sizeOf(macho.section_64);
286 self.inner.nsects += 1;
287 }
288
289 pub fn read(alloc: *Allocator, reader: anytype) !SegmentCommand {221 pub fn read(alloc: *Allocator, reader: anytype) !SegmentCommand {
290 const inner = try reader.readStruct(macho.segment_command_64);222 const inner = try reader.readStruct(macho.segment_command_64);
291 var segment = SegmentCommand{223 var segment = SegmentCommand{
...@@ -427,13 +359,6 @@ pub fn createLoadDylibCommand(...@@ -427,13 +359,6 @@ pub fn createLoadDylibCommand(
427 return dylib_cmd;359 return dylib_cmd;
428}360}
429361
430fn makeStaticString(bytes: []const u8) [16]u8 {
431 var buf = [_]u8{0} ** 16;
432 assert(bytes.len <= buf.len);
433 mem.copy(u8, &buf, bytes);
434 return buf;
435}
436
437fn parseName(name: *const [16]u8) []const u8 {362fn parseName(name: *const [16]u8) []const u8 {
438 const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;363 const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
439 return name[0..len];364 return name[0..len];
...@@ -513,34 +438,26 @@ test "read-write segment command" {...@@ -513,34 +438,26 @@ test "read-write segment command" {
513 0x00, 0x00, 0x00, 0x00, // reserved3438 0x00, 0x00, 0x00, 0x00, // reserved3
514 };439 };
515 var cmd = SegmentCommand{440 var cmd = SegmentCommand{
516 .inner = .{441 .inner = macho.segment_command_64.new(.{
517 .cmd = macho.LC_SEGMENT_64,
518 .cmdsize = 152,442 .cmdsize = 152,
519 .segname = makeStaticString("__TEXT"),443 .segname = makeStaticString("__TEXT"),
520 .vmaddr = 4294967296,444 .vmaddr = 4294967296,
521 .vmsize = 294912,445 .vmsize = 294912,
522 .fileoff = 0,
523 .filesize = 294912,446 .filesize = 294912,
524 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE,447 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE,
525 .initprot = macho.VM_PROT_EXECUTE | macho.VM_PROT_READ,448 .initprot = macho.VM_PROT_EXECUTE | macho.VM_PROT_READ,
526 .nsects = 1,449 .nsects = 1,
527 .flags = 0,450 }),
528 },
529 };451 };
530 try cmd.sections.append(gpa, .{452 try cmd.sections.append(gpa, macho.section_64.new(.{
531 .sectname = makeStaticString("__text"),453 .sectname = makeStaticString("__text"),
532 .segname = makeStaticString("__TEXT"),454 .segname = makeStaticString("__TEXT"),
533 .addr = 4294983680,455 .addr = 4294983680,
534 .size = 448,456 .size = 448,
535 .offset = 16384,457 .offset = 16384,
536 .@"align" = 2,458 .@"align" = 2,
537 .reloff = 0,
538 .nreloc = 0,
539 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,459 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
540 .reserved1 = 0,460 }));
541 .reserved2 = 0,
542 .reserved3 = 0,
543 });
544 defer cmd.deinit(gpa);461 defer cmd.deinit(gpa);
545 try testRead(gpa, in_buffer, LoadCommand{ .Segment = cmd });462 try testRead(gpa, in_buffer, LoadCommand{ .Segment = cmd });
546463