summaryrefslogtreecommitdiff
path: root/output
diff options
context:
space:
mode:
authorDavid DeHaven <dave@sagetv.com>2008-12-09 00:18:43 -0800
committerH. Peter Anvin <hpa@zytor.com>2008-12-18 14:58:24 -0800
commit74a8755fe3ea755183c2a70a9fcf1a478dda2d68 (patch)
tree434653e7a948375fa1cd714f882867a89da8ea05 /output
parent352fe06e02034394107e2ad625018eff731a9b01 (diff)
downloadnasm-74a8755fe3ea755183c2a70a9fcf1a478dda2d68.tar.gz
nasm-74a8755fe3ea755183c2a70a9fcf1a478dda2d68.tar.bz2
nasm-74a8755fe3ea755183c2a70a9fcf1a478dda2d68.zip
Mach-O alignment fix
Several projects have taken to using .text to store read-only data when building on Mac OS X due to crashes in SSE code from the .rodata section being mis-aligned. It seems there was a misunderstanding about how ld/ld64 handles section alignment in outmacho.c so I wrote a patch to fix it. I tested it against x264 git, modified it to use ".rodata align=16" for the data section and use movdqa instructions (guaranteed to crash when built with unpatched nasm) and it passed all tests in its checkasm tool. If you want more data I can provide, but it's late and I've had a couple glasses of mulled wine :) -DrD-
Diffstat (limited to 'output')
-rw-r--r--output/outmacho.c31
1 files changed, 21 insertions, 10 deletions
diff --git a/output/outmacho.c b/output/outmacho.c
index 06ae8ee..30234a9 100644
--- a/output/outmacho.c
+++ b/output/outmacho.c
@@ -63,6 +63,7 @@ struct section {
/* data that goes into the file */
char sectname[16]; /* what this section is called */
char segname[16]; /* segment this section will be in */
+ uint32_t addr; /* in-memory address (subject to alignment) */
uint32_t size; /* in-memory and -file size */
uint32_t nreloc; /* relocation entry count */
uint32_t flags; /* type and attributes (masked) */
@@ -815,11 +816,24 @@ static void macho_calculate_sizes (void)
/* count sections and calculate in-memory and in-file offsets */
for (s = sects; s != NULL; s = s->next) {
+ uint32_t pad = 0;
+
/* zerofill sections aren't actually written to the file */
if ((s->flags & SECTION_TYPE) != S_ZEROFILL)
seg_filesize += s->size;
- seg_vmsize += s->size;
+ /* recalculate segment address based on alignment and vm size */
+ s->addr = seg_vmsize;
+ /* we need section alignment to calculate final section address */
+ if (s->align == -1)
+ s->align = DEFAULT_SECTION_ALIGNMENT;
+ if(s->align) {
+ uint32_t newaddr = align(s->addr, 1 << s->align);
+ pad = newaddr - s->addr;
+ s->addr = newaddr;
+ }
+
+ seg_vmsize += s->size + pad;
++seg_nsects;
}
@@ -854,7 +868,6 @@ static void macho_write_header (void)
static uint32_t macho_write_segment (uint32_t offset)
{
- uint32_t s_addr = 0;
uint32_t rel_base = alignint32_t (offset + seg_filesize);
uint32_t s_reloff = 0;
struct section *s;
@@ -881,7 +894,7 @@ static uint32_t macho_write_segment (uint32_t offset)
for (s = sects; s != NULL; s = s->next) {
fwrite(s->sectname, sizeof(s->sectname), 1, machofp);
fwrite(s->segname, sizeof(s->segname), 1, machofp);
- fwriteint32_t(s_addr, machofp);
+ fwriteint32_t(s->addr, machofp);
fwriteint32_t(s->size, machofp);
/* dummy data for zerofill sections or proper values */
@@ -909,8 +922,6 @@ static uint32_t macho_write_segment (uint32_t offset)
fwriteint32_t(s->flags, machofp); /* flags */
fwriteint32_t(0, machofp); /* reserved */
fwriteint32_t(0, machofp); /* reserved */
-
- s_addr += s->size;
}
rel_padcnt = rel_base - offset;
@@ -946,7 +957,7 @@ static void macho_write_section (void)
struct section *s, *s2;
struct reloc *r;
char *rel_paddata = "\0\0\0";
- uint8_t fi, *p, *q, blk[4];
+ uint8_t *p, *q, blk[4];
int32_t l;
for (s = sects; s != NULL; s = s->next) {
@@ -980,10 +991,10 @@ static void macho_write_section (void)
offset which we already have. The linker takes care
of the rest of the address. */
if (!r->ext) {
- /* add sizes of previous sections to current offset */
- for (s2 = sects, fi = 1;
- s2 != NULL && fi < r->snum; s2 = s2->next, fi++)
- l += s2->size;
+ /* generate final address by section address and offset */
+ s2 = get_section_by_index(r->snum);
+ if(s2)
+ l += s2->addr; // else what?!?
}
/* write new offset back */