summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtem Pyanykh <artempyanykh@gmail.com>2019-02-11 14:05:26 +0300
committerMarge Bot <ben+marge-bot@smart-cactus.org>2019-03-20 19:52:39 -0400
commit78c61acf15c66a17df63da60226acff3a2dda585 (patch)
tree6278c767c639f571511e07d2cba9410000b69aac
parent368187591a5454e47c4e08dae90d39d2af1fad40 (diff)
downloadhaskell-78c61acf15c66a17df63da60226acff3a2dda585.tar.gz
Use segments for section layout
-rw-r--r--rts/Linker.c50
-rw-r--r--rts/LinkerInternals.h25
-rw-r--r--rts/RtsUtils.c6
-rw-r--r--rts/RtsUtils.h2
-rw-r--r--rts/linker/MachO.c303
-rw-r--r--rts/linker/MachO.h4
6 files changed, 296 insertions, 94 deletions
diff --git a/rts/Linker.c b/rts/Linker.c
index ba78efe7b6..3d56989677 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -1195,6 +1195,7 @@ void freeObjectCode (ObjectCode *oc)
}
freeProddableBlocks(oc);
+ freeSegments(oc);
/* Free symbol_extras. On x86_64 Windows, symbol_extras are allocated
* alongside the image, so we don't need to free. */
@@ -1279,6 +1280,8 @@ mkOc( pathchar *path, char *image, int imageSize,
oc->symbols = NULL;
oc->n_sections = 0;
oc->sections = NULL;
+ oc->n_segments = 0;
+ oc->segments = NULL;
oc->proddables = NULL;
oc->stable_ptrs = NULL;
#if defined(NEED_SYMBOL_EXTRAS)
@@ -1840,3 +1843,50 @@ addSection (Section *s, SectionKind kind, SectionAlloc alloc,
start, (void*)((StgWord)start + size),
size, kind ));
}
+
+/* -----------------------------------------------------------------------------
+ * Segment management
+ */
+void
+initSegment (Segment *s, void *start, size_t size, SegmentProt prot, int n_sections)
+{
+ s->start = start;
+ s->size = size;
+ s->prot = prot;
+ s->sections_idx = (int *)stgCallocBytes(n_sections, sizeof(int),
+ "initSegment(segment)");
+ s->n_sections = n_sections;
+}
+
+void freeSegments (ObjectCode *oc)
+{
+ if (oc->segments != NULL) {
+ IF_DEBUG(linker, debugBelch("freeSegments: freeing %d segments\n", oc->n_segments));
+
+ for (int i = 0; i < oc->n_segments; i++) {
+ Segment *s = &oc->segments[i];
+
+ IF_DEBUG(linker, debugBelch("freeSegments: freeing segment %d at %p size %zu\n",
+ i, s->start, s->size));
+
+ stgFree(s->sections_idx);
+ s->sections_idx = NULL;
+
+ if (0 == s->size) {
+ IF_DEBUG(linker, debugBelch("freeSegment: skipping segment of 0 size\n"));
+ continue;
+ } else {
+#if RTS_LINKER_USE_MMAP
+ CHECKM(0 == munmap(s->start, s->size), "freeSegments: failed to unmap memory");
+#else
+ stgFree(s->start);
+#endif
+ }
+ s->start = NULL;
+ }
+
+ stgFree(oc->segments);
+ oc->segments = NULL;
+ }
+}
+
diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
index 81a09fe3ae..cd36fd55d2 100644
--- a/rts/LinkerInternals.h
+++ b/rts/LinkerInternals.h
@@ -62,6 +62,11 @@ typedef
}
SectionAlloc;
+typedef enum {
+ SEGMENT_PROT_RX,
+ SEGMENT_PROT_RW
+} SegmentProt;
+
/*
* Note [No typedefs for customizable types]
* Some pointer-to-struct types are defined opaquely
@@ -103,6 +108,18 @@ typedef
}
ProddableBlock;
+typedef struct _Segment {
+ void *start; /* page aligned start address of a segment */
+ size_t size; /* page rounded size of a segment */
+ SegmentProt prot; /* mem protection to set after all symbols were
+ * resolved */
+
+ int *sections_idx; /* an array of section indexes assigned to this segment */
+ int n_sections;
+} Segment;
+
+/* todo (AP): add freeSegments */
+
/*
* We must keep track of the StablePtrs that are created for foreign
* exports by constructor functions when the module is loaded, so that
@@ -179,9 +196,14 @@ typedef struct _ObjectCode {
/* The section-kind entries for this object module. Linked
list. */
+ /* fixme (AP): doesn't look like a linked list. On MachO it's an array, and
+ * generally Section struct doesn't have pointers to next. */
int n_sections;
Section* sections;
+ int n_segments;
+ Segment *segments;
+
/* Allow a chain of these things */
struct _ObjectCode * next;
@@ -312,6 +334,9 @@ ObjectCode* mkOc( pathchar *path, char *image, int imageSize,
int misalignment
);
+void initSegment(Segment *s, void *start, size_t size, SegmentProt prot, int n_sections);
+void freeSegments(ObjectCode *oc);
+
/* MAP_ANONYMOUS is MAP_ANON on some systems,
e.g. OS X (before Sierra), OpenBSD etc */
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
diff --git a/rts/RtsUtils.c b/rts/RtsUtils.c
index d5fa16874c..b099fa2dad 100644
--- a/rts/RtsUtils.c
+++ b/rts/RtsUtils.c
@@ -97,13 +97,13 @@ stgReallocBytes (void *p, size_t n, char *msg)
}
void *
-stgCallocBytes (size_t n, size_t m, char *msg)
+stgCallocBytes (size_t count, size_t size, char *msg)
{
void *space;
- if ((space = calloc(n, m)) == NULL) {
+ if ((space = calloc(count, size)) == NULL) {
/* don't fflush(stdout); WORKAROUND bug in Linux glibc */
- rtsConfig.mallocFailHook((W_) n*m, msg);
+ rtsConfig.mallocFailHook((W_) count*size, msg);
stg_exit(EXIT_INTERNAL_ERROR);
}
return space;
diff --git a/rts/RtsUtils.h b/rts/RtsUtils.h
index 49712c0d47..5c986fe4a2 100644
--- a/rts/RtsUtils.h
+++ b/rts/RtsUtils.h
@@ -22,7 +22,7 @@ void *stgMallocBytes(size_t n, char *msg)
void *stgReallocBytes(void *p, size_t n, char *msg);
-void *stgCallocBytes(size_t n, size_t m, char *msg)
+void *stgCallocBytes(size_t count, size_t size, char *msg)
GNUC3_ATTRIBUTE(__malloc__);
char *stgStrndup(const char *s, size_t n);
diff --git a/rts/linker/MachO.c b/rts/linker/MachO.c
index 7ec3cabef7..772ae21274 100644
--- a/rts/linker/MachO.c
+++ b/rts/linker/MachO.c
@@ -1021,18 +1021,163 @@ relocateSection(ObjectCode* oc, int curSection)
* addressability for relative or absolute access.
*/
-size_t ocGetRequiredSpace_MachO(ObjectCode* oc)
+SectionKind
+getSectionKind_MachO(MachOSection *section)
{
- size_t bytesNeeded = 0;
- size_t sectionSize;
+ SectionKind kind;
+
+ /* todo: Use section flags instead */
+ if (0==strcmp(section->sectname,"__text")) {
+ kind = SECTIONKIND_CODE_OR_RODATA;
+ } else if (0==strcmp(section->sectname,"__const") ||
+ 0==strcmp(section->sectname,"__data") ||
+ 0==strcmp(section->sectname,"__bss") ||
+ 0==strcmp(section->sectname,"__common") ||
+ 0==strcmp(section->sectname,"__mod_init_func")) {
+ kind = SECTIONKIND_RWDATA;
+ } else {
+ kind = SECTIONKIND_OTHER;
+ }
- for(int i = 0; i < oc->n_sections; i++)
+ return kind;
+}
+
+/* Calculate the # of active segments and their sizes based on section
+ * sizes and alignments. This is done in 2 passes over sections:
+ * 1. Calculate how many sections is going to be in each segment and
+ * the total segment size.
+ * 2. Fill in segment's sections_idx arrays.
+ *
+ * gbZerofillSegment is there because of this comment in mach-o/loader.h:
+ * The gigabyte zero fill sections, those with the section type
+ * S_GB_ZEROFILL, can only be in a segment with sections of this
+ * type. These segments are then placed after all other segments.
+ */
+int
+ocBuildSegments_MachO(ObjectCode *oc)
+{
+ int n_rxSections = 0;
+ size_t size_rxSegment = 0;
+ Segment *rxSegment = NULL;
+
+ int n_rwSections = 0;
+ size_t size_rwSegment = 0;
+ Segment *rwSegment = NULL;
+
+ int n_gbZerofills = 0;
+ size_t size_gbZerofillSegment = 0;
+ Segment *gbZerofillSegment = NULL;
+
+ int n_activeSegments = 0;
+ int curSegment = 0;
+ size_t size_compound;
+
+ Segment *segments = NULL;
+ void *mem = NULL, *curMem = NULL;
+
+ for (int i = 0; i < oc->n_sections; i++) {
+ MachOSection *macho = &oc->info->macho_sections[i];
+ size_t alignment = 1 << macho->align;
+
+ if (S_GB_ZEROFILL == (macho->flags & SECTION_TYPE)) {
+ size_gbZerofillSegment = roundUpToAlign(size_gbZerofillSegment, alignment);
+ size_gbZerofillSegment += macho->size;
+ n_gbZerofills++;
+ } else if (getSectionKind_MachO(macho) == SECTIONKIND_CODE_OR_RODATA) {
+ size_rxSegment = roundUpToAlign(size_rxSegment, alignment);
+ size_rxSegment += macho->size;
+ n_rxSections++;
+ } else {
+ size_rwSegment = roundUpToAlign(size_rwSegment, alignment);
+ size_rwSegment += macho->size;
+ n_rwSections++;
+ }
+ }
+
+ size_compound = roundUpToPage(size_rxSegment) +
+ roundUpToPage(size_rwSegment) +
+ roundUpToPage(size_gbZerofillSegment);
+
+ if (n_rxSections > 0) {
+ n_activeSegments++;
+ }
+ if (n_rwSections > 0) {
+ n_activeSegments++;
+ }
+ if (n_gbZerofills >0) {
+ n_activeSegments++;
+ }
+
+ mem = mmapForLinker(size_compound, MAP_ANON, -1, 0);
+ if (NULL == mem) return 0;
+
+ IF_DEBUG(linker, debugBelch("ocBuildSegments: allocating %d segments\n", n_activeSegments));
+ segments = (Segment*)stgCallocBytes(n_activeSegments, sizeof(Segment),
+ "ocBuildSegments_MachO(segments)");
+ curMem = mem;
+
+ /* Allocate space for RX segment */
+ if (n_rxSections > 0) {
+ rxSegment = &segments[curSegment];
+ initSegment(rxSegment,
+ curMem,
+ roundUpToPage(size_rxSegment),
+ SEGMENT_PROT_RX,
+ n_rxSections);
+ IF_DEBUG(linker, debugBelch("ocBuildSegments_MachO: init segment %d (RX) at %p size %zu\n",
+ curSegment, rxSegment->start, rxSegment->size));
+ curMem = (char *)curMem + rxSegment->size;
+ curSegment++;
+ }
+
+ /* Allocate space for RW segment */
+ if (n_rwSections > 0) {
+ rwSegment = &segments[curSegment];
+ initSegment(rwSegment,
+ curMem,
+ roundUpToPage(size_rwSegment),
+ SEGMENT_PROT_RW,
+ n_rwSections);
+ IF_DEBUG(linker, debugBelch("ocBuildSegments_MachO: init segment %d (RW) at %p size %zu\n",
+ curSegment, rwSegment->start, rwSegment->size));
+ curMem = (char *)curMem + rwSegment->size;
+ curSegment++;
+ }
+
+ /* Allocate space for GB_ZEROFILL segment */
+ if (n_gbZerofills > 0) {
+ gbZerofillSegment = &segments[curSegment];
+ initSegment(gbZerofillSegment,
+ curMem,
+ roundUpToPage(size_gbZerofillSegment),
+ SEGMENT_PROT_RW,
+ n_gbZerofills);
+ IF_DEBUG(linker, debugBelch("ocBuildSegments_MachO: init segment %d (GB_ZEROFILL) at %p size %zu\n",
+ curSegment, gbZerofillSegment->start, gbZerofillSegment->size));
+ curMem = (char *)curMem + gbZerofillSegment->size;
+ curSegment++;
+ }
+
+ /* Second pass over sections to fill in sections_idx arrays */
+ for (int i = 0, rx = 0, rw = 0, gb = 0;
+ i < oc->n_sections;
+ i++)
{
- sectionSize = oc->info->macho_sections[i].size;
- bytesNeeded += roundUpToPage(sectionSize);
+ MachOSection *macho = &oc->info->macho_sections[i];
+
+ if (S_GB_ZEROFILL == (macho->flags & SECTION_TYPE)) {
+ gbZerofillSegment->sections_idx[gb++] = i;
+ } else if (getSectionKind_MachO(macho) == SECTIONKIND_CODE_OR_RODATA) {
+ rxSegment->sections_idx[rx++] = i;
+ } else {
+ rwSegment->sections_idx[rw++] = i;
+ }
}
- return bytesNeeded;
+ oc->segments = segments;
+ oc->n_segments = n_activeSegments;
+
+ return 1;
}
int
@@ -1048,27 +1193,16 @@ ocGetNames_MachO(ObjectCode* oc)
Section *secArray;
secArray = (Section*)stgCallocBytes(
- sizeof(Section),
- oc->info->segCmd->nsects,
- "ocGetNames_MachO(sections)");
+ oc->info->segCmd->nsects,
+ sizeof(Section),
+ "ocGetNames_MachO(sections)");
oc->sections = secArray;
IF_DEBUG(linker, debugBelch("ocGetNames_MachO: will load %d sections\n",
oc->n_sections));
-#if defined(darwin_HOST_OS)
- size_t requiredSize = ocGetRequiredSpace_MachO(oc);
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: required mmaped space is %zu\n",
- requiredSize));
-
- void* memStart = mmapForLinker(requiredSize, MAP_ANONYMOUS, -1, 0);
- if (memStart == NULL) {
- barf("ocGetNames_MachO: failed to mmap");
- }
- void* memCur = memStart;
-#endif // darwin_HOST_OS
-
+#if defined (ios_HOST_OS)
for(int i=0; i < oc->n_sections; i++)
{
MachOSection * section = &oc->info->macho_sections[i];
@@ -1080,23 +1214,9 @@ ocGetNames_MachO(ObjectCode* oc)
continue;
}
- // XXX, use SECTION_TYPE attributes, instead of relying on the name?
-
- SectionKind kind = SECTIONKIND_OTHER;
-
- if (0==strcmp(section->sectname,"__text")) {
- kind = SECTIONKIND_CODE_OR_RODATA;
- }
- else if (0==strcmp(section->sectname,"__const") ||
- 0==strcmp(section->sectname,"__data") ||
- 0==strcmp(section->sectname,"__bss") ||
- 0==strcmp(section->sectname,"__common") ||
- 0==strcmp(section->sectname,"__mod_init_func")) {
- kind = SECTIONKIND_RWDATA;
- }
+ SectionKind kind = getSectionKind_MachO(section);
switch(section->flags & SECTION_TYPE) {
-#if defined(ios_HOST_OS)
case S_ZEROFILL:
case S_GB_ZEROFILL: {
// See Note [mmap r+w+x]
@@ -1105,7 +1225,8 @@ ocGetNames_MachO(ObjectCode* oc)
MAP_ANON | MAP_PRIVATE,
-1, 0);
if( mem == MAP_FAILED ) {
- barf("failed to mmap allocate memory for zerofill section %d of size %d. errno = %d", i, section->size, errno);
+ barf("failed to mmap allocate memory for zerofill section %d of size %d. errno = %d",
+ i, section->size, errno);
}
addSection(&secArray[i], kind, SECTION_MMAP, mem, section->size,
0, mem, roundUpToPage(section->size));
@@ -1177,72 +1298,76 @@ ocGetNames_MachO(ObjectCode* oc)
= (MachORelocationInfo*)(oc->image + section->reloff);
break;
}
+ }
+ }
+#else /* !ios_HOST_OS */
+ IF_DEBUG(linker, debugBelch("ocGetNames_MachO: building segments\n"));
-#else /* any other host */
- case S_ZEROFILL:
- case S_GB_ZEROFILL: {
- char * zeroFillArea;
- if (RTS_LINKER_USE_MMAP) {
- zeroFillArea = mmapForLinker(section->size, MAP_ANONYMOUS,
- -1, 0);
- if (zeroFillArea == NULL) return 0;
- memset(zeroFillArea, 0, section->size);
- }
- else {
- zeroFillArea = stgCallocBytes(1,section->size,
- "ocGetNames_MachO(common symbols)");
- }
- section->offset = zeroFillArea - oc->image; // fixme: fails down the road
- // when zFA < oc->image since offset is unsigned
+ CHECKM(ocBuildSegments_MachO(oc), "ocGetNames_MachO: failed to build segments\n");
+
+ for (int seg_n = 0; seg_n < oc->n_segments; seg_n++) {
+ Segment *segment = &oc->segments[seg_n];
+ void *curMem = segment->start;
- addSection(&secArray[i], kind, SECTION_NOMEM, // fixme: why NOMEM?
- (void *)(oc->image + section->offset),
- section->size,
- 0, 0, 0);
+ IF_DEBUG(linker,
+ debugBelch("ocGetNames_MachO: loading segment %d "
+ "(address = %p, size = %zu) "
+ "with %d sections\n",
+ seg_n, segment->start, segment->size, segment->n_sections));
- addProddableBlock(oc,
- (void *) (oc->image + section->offset),
- section->size);
+ for (int sec_n = 0; sec_n < segment->n_sections; sec_n++) {
+ int sec_idx = segment->sections_idx[sec_n];
+ MachOSection *section = &oc->info->macho_sections[sec_idx];
- secArray[i].info->nstubs = 0;
- secArray[i].info->stub_offset = NULL;
- secArray[i].info->stub_size = 0;
- secArray[i].info->stubs = NULL;
+ size_t alignment = 1 << section->align;
+ SectionKind kind = getSectionKind_MachO(section);
- secArray[i].info->macho_section = section;
- secArray[i].info->relocation_info
- = (MachORelocationInfo*)(oc->image + section->reloff);
+ void *secMem = (void *)roundUpToAlign((size_t)curMem, alignment);
+
+ IF_DEBUG(linker,
+ debugBelch("ocGetNames_MachO: loading section %d in segment %d "
+ "(#%d, %s %s)\n"
+ " skipped %zu bytes due to alignment of %zu\n",
+ sec_n, seg_n, sec_idx, section->segname, section->sectname,
+ (char *)secMem - (char *)curMem, alignment));
+
+ switch (section->flags & SECTION_TYPE) {
+ case S_ZEROFILL:
+ case S_GB_ZEROFILL:
+ IF_DEBUG(linker, debugBelch("ocGetNames_MachO: memset to 0 a ZEROFILL section\n"));
+ memset(secMem, 0, section->size);
break;
+ default:
+ IF_DEBUG(linker,
+ debugBelch("ocGetNames_MachO: copying from %p to %p"
+ " a block of %" PRIu64 " bytes\n",
+ (void *) (oc->image + section->offset), secMem, section->size));
+
+ memcpy(secMem, oc->image + section->offset, section->size);
}
- default: {
- size_t sectionRoundedSize = roundUpToPage(section->size);
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: copying from %p to %p a block of %" PRIu64 " bytes\n",
- (void *) (oc->image + section->offset), memCur, section->size));
- memcpy(memCur, oc->image + section->offset, section->size);
- IF_DEBUG(linker, debugBelch("ocGetNames_MachO: copied %" PRIu64 " bytes\n",
- section->size));
+ /* SECTION_NOMEM since memory is already allocated in segments */
+ addSection(&secArray[sec_idx], kind, SECTION_NOMEM,
+ secMem, section->size,
+ 0, 0, 0);
+ addProddableBlock(oc, secMem, section->size);
- addSection(&secArray[i], kind, SECTION_MMAP,
- memCur, section->size,
- 0, memCur, sectionRoundedSize);
- addProddableBlock(oc, memCur, section->size);
+ curMem = (char*) secMem + section->size;
- memCur = (char*) memCur + sectionRoundedSize;
+ secArray[sec_idx].info->nstubs = 0;
+ secArray[sec_idx].info->stub_offset = NULL;
+ secArray[sec_idx].info->stub_size = 0;
+ secArray[sec_idx].info->stubs = NULL;
- secArray[i].info->nstubs = 0;
- secArray[i].info->stub_offset = NULL;
- secArray[i].info->stub_size = 0;
- secArray[i].info->stubs = NULL;
-
- secArray[i].info->macho_section = section;
- secArray[i].info->relocation_info
+ secArray[sec_idx].info->macho_section = section;
+ secArray[sec_idx].info->relocation_info
= (MachORelocationInfo*)(oc->image + section->reloff);
- }
-#endif
+
}
}
+#endif
+
/* now, as all sections have been loaded, we can resolve the absolute
* address of symbols defined in those sections.
*/
diff --git a/rts/linker/MachO.h b/rts/linker/MachO.h
index 20cb2d061a..518c2ce569 100644
--- a/rts/linker/MachO.h
+++ b/rts/linker/MachO.h
@@ -9,11 +9,13 @@
void ocInit_MachO ( ObjectCode* oc );
void ocDeinit_MachO ( ObjectCode* oc );
int ocVerifyImage_MachO ( ObjectCode* oc );
-size_t ocGetRequiredSpace_MachO ( ObjectCode* oc);
+int ocBuildSegments_MachO ( ObjectCode* oc );
int ocGetNames_MachO ( ObjectCode* oc );
int ocResolve_MachO ( ObjectCode* oc );
int ocRunInit_MachO ( ObjectCode* oc );
int machoGetMisalignment ( FILE * );
int ocAllocateExtras_MachO ( ObjectCode* oc );
+SectionKind getSectionKind_MachO ( MachOSection *macho );
+
#include "EndPrivate.h"