@@ -4085,6 +4085,70 @@ fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64
4085
4085
return mem .alignForwardGeneric (u64 , final_off , alignment );
4086
4086
}
4087
4087
4088
+ fn growSegment (self : * MachO , seg_id : u16 , new_size : u64 ) ! void {
4089
+ const seg = & self .load_commands .items [seg_id ].Segment ;
4090
+ const new_seg_size = mem .alignForwardGeneric (u64 , new_size , self .page_size );
4091
+ assert (new_seg_size > seg .inner .filesize );
4092
+ const offset_amt = new_seg_size - seg .inner .filesize ;
4093
+ log .debug ("growing segment {s} from 0x{x} to 0x{x}" , .{ seg .inner .segname , seg .inner .filesize , new_seg_size });
4094
+ seg .inner .filesize = new_seg_size ;
4095
+ seg .inner .vmsize = new_seg_size ;
4096
+
4097
+ log .debug (" (new segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))" , .{
4098
+ seg .inner .fileoff ,
4099
+ seg .inner .fileoff + seg .inner .filesize ,
4100
+ seg .inner .vmaddr ,
4101
+ seg .inner .vmaddr + seg .inner .vmsize ,
4102
+ });
4103
+
4104
+ // TODO We should probably nop the expanded by distance, or put 0s.
4105
+
4106
+ // TODO copyRangeAll doesn't automatically extend the file on macOS.
4107
+ const ledit_seg = & self .load_commands .items [self .linkedit_segment_cmd_index .? ].Segment ;
4108
+ const new_filesize = offset_amt + ledit_seg .inner .fileoff + ledit_seg .inner .filesize ;
4109
+ try self .base .file .? .pwriteAll (&[_ ]u8 {0 }, new_filesize - 1 );
4110
+
4111
+ var next : usize = seg_id + 1 ;
4112
+ while (next < self .linkedit_segment_cmd_index .? + 1 ) : (next += 1 ) {
4113
+ const next_seg = & self .load_commands .items [next ].Segment ;
4114
+ _ = try self .base .file .? .copyRangeAll (
4115
+ next_seg .inner .fileoff ,
4116
+ self .base .file .? ,
4117
+ next_seg .inner .fileoff + offset_amt ,
4118
+ next_seg .inner .filesize ,
4119
+ );
4120
+ next_seg .inner .fileoff += offset_amt ;
4121
+ next_seg .inner .vmaddr += offset_amt ;
4122
+
4123
+ log .debug (" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))" , .{
4124
+ next_seg .inner .segname ,
4125
+ next_seg .inner .fileoff ,
4126
+ next_seg .inner .fileoff + next_seg .inner .filesize ,
4127
+ next_seg .inner .vmaddr ,
4128
+ next_seg .inner .vmaddr + next_seg .inner .vmsize ,
4129
+ });
4130
+
4131
+ for (next_seg .sections .items ) | * moved_sect , moved_sect_id | {
4132
+ moved_sect .offset += @intCast (u32 , offset_amt );
4133
+ moved_sect .addr += offset_amt ;
4134
+
4135
+ log .debug (" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))" , .{
4136
+ commands .segmentName (moved_sect .* ),
4137
+ commands .sectionName (moved_sect .* ),
4138
+ moved_sect .offset ,
4139
+ moved_sect .offset + moved_sect .size ,
4140
+ moved_sect .addr ,
4141
+ moved_sect .addr + moved_sect .size ,
4142
+ });
4143
+
4144
+ try self .allocateLocalSymbols (.{
4145
+ .seg = @intCast (u16 , next ),
4146
+ .sect = @intCast (u16 , moved_sect_id ),
4147
+ }, @intCast (i64 , offset_amt ));
4148
+ }
4149
+ }
4150
+ }
4151
+
4088
4152
fn growSection (self : * MachO , match : MatchingSection , new_size : u32 ) ! void {
4089
4153
const tracy = trace (@src ());
4090
4154
defer tracy .end ();
@@ -4098,7 +4162,14 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
4098
4162
const needed_size = mem .alignForwardGeneric (u32 , ideal_size , alignment );
4099
4163
4100
4164
if (needed_size > max_size ) blk : {
4101
- log .debug (" (need to grow!)" , .{});
4165
+ log .debug (" (need to grow! needed 0x{x}, max 0x{x})" , .{ needed_size , max_size });
4166
+
4167
+ if (match .sect == seg .sections .items .len - 1 ) {
4168
+ // Last section, just grow segments
4169
+ try self .growSegment (match .seg , seg .inner .filesize + needed_size - max_size );
4170
+ break :blk ;
4171
+ }
4172
+
4102
4173
// Need to move all sections below in file and address spaces.
4103
4174
const offset_amt = offset : {
4104
4175
const max_alignment = try self .getSectionMaxAlignment (match .seg , match .sect + 1 );
@@ -4114,70 +4185,10 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
4114
4185
4115
4186
if (last_sect_off + offset_amt > seg_off ) {
4116
4187
// Need to grow segment first.
4117
- log .debug (" (need to grow segment first)" , .{});
4118
4188
const spill_size = (last_sect_off + offset_amt ) - seg_off ;
4119
- const seg_offset_amt = mem .alignForwardGeneric (u64 , spill_size , self .page_size );
4120
- seg .inner .filesize += seg_offset_amt ;
4121
- seg .inner .vmsize += seg_offset_amt ;
4122
-
4123
- log .debug (" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))" , .{
4124
- seg .inner .segname ,
4125
- seg .inner .fileoff ,
4126
- seg .inner .fileoff + seg .inner .filesize ,
4127
- seg .inner .vmaddr ,
4128
- seg .inner .vmaddr + seg .inner .vmsize ,
4129
- });
4130
-
4131
- // TODO We should probably nop the expanded by distance, or put 0s.
4132
-
4133
- // TODO copyRangeAll doesn't automatically extend the file on macOS.
4134
- const ledit_seg = & self .load_commands .items [self .linkedit_segment_cmd_index .? ].Segment ;
4135
- const new_filesize = seg_offset_amt + ledit_seg .inner .fileoff + ledit_seg .inner .filesize ;
4136
- try self .base .file .? .pwriteAll (&[_ ]u8 {0 }, new_filesize - 1 );
4137
-
4138
- var next : usize = match .seg + 1 ;
4139
- while (next < self .linkedit_segment_cmd_index .? + 1 ) : (next += 1 ) {
4140
- const next_seg = & self .load_commands .items [next ].Segment ;
4141
- _ = try self .base .file .? .copyRangeAll (
4142
- next_seg .inner .fileoff ,
4143
- self .base .file .? ,
4144
- next_seg .inner .fileoff + seg_offset_amt ,
4145
- next_seg .inner .filesize ,
4146
- );
4147
- next_seg .inner .fileoff += seg_offset_amt ;
4148
- next_seg .inner .vmaddr += seg_offset_amt ;
4149
-
4150
- log .debug (" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))" , .{
4151
- next_seg .inner .segname ,
4152
- next_seg .inner .fileoff ,
4153
- next_seg .inner .fileoff + next_seg .inner .filesize ,
4154
- next_seg .inner .vmaddr ,
4155
- next_seg .inner .vmaddr + next_seg .inner .vmsize ,
4156
- });
4157
-
4158
- for (next_seg .sections .items ) | * moved_sect , moved_sect_id | {
4159
- moved_sect .offset += @intCast (u32 , seg_offset_amt );
4160
- moved_sect .addr += seg_offset_amt ;
4161
-
4162
- log .debug (" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))" , .{
4163
- commands .segmentName (moved_sect .* ),
4164
- commands .sectionName (moved_sect .* ),
4165
- moved_sect .offset ,
4166
- moved_sect .offset + moved_sect .size ,
4167
- moved_sect .addr ,
4168
- moved_sect .addr + moved_sect .size ,
4169
- });
4170
-
4171
- try self .allocateLocalSymbols (.{
4172
- .seg = @intCast (u16 , next ),
4173
- .sect = @intCast (u16 , moved_sect_id ),
4174
- }, @intCast (i64 , seg_offset_amt ));
4175
- }
4176
- }
4189
+ try self .growSegment (match .seg , seg .inner .filesize + spill_size );
4177
4190
}
4178
4191
4179
- if (match .sect + 1 >= seg .sections .items .len ) break :blk ;
4180
-
4181
4192
// We have enough space to expand within the segment, so move all sections by
4182
4193
// the required amount and update their header offsets.
4183
4194
const next_sect = seg .sections .items [match .sect + 1 ];
0 commit comments