mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-01-30 16:41:05 +08:00
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-
This commit is contained in:
parent
352fe06e02
commit
74a8755fe3
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user