From cb9a459560068aa96481a3c424a97cd6d84d9061 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 20 Nov 2010 14:18:23 +0300 Subject: coff: Handle massive relocations The backport of 4db724fdd76e3a6cd0f5124ef86de976c495d666 359b63f8976375f071edc33092daea57efa768fb 01102ee8e6a967830bcd6f0134efe8976f473121 2672af737954fb17ec0ebf17e787219a504c4400 so coff output target to be able to handle massive relocations. Signed-off-by: Cyrill Gorcunov --- output/outcoff.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- output/pecoff.h | 2 ++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/output/outcoff.c b/output/outcoff.c index 5b232bb9..5c1de013 100644 --- a/output/outcoff.c +++ b/output/outcoff.c @@ -837,6 +837,25 @@ static int coff_directives(enum directives directive, char *value, int pass) } } +/* handle relocations storm, valid for win32/64 only */ +static inline void coff_adjust_relocs(struct Section *s) +{ + if (s->nrelocs < IMAGE_SCN_MAX_RELOC) + return; +#ifdef OF_COFF + else + { + if (ofmt == &of_coff) + nasm_error(ERR_FATAL, + "Too many relocations (%d) for section `%s'", + s->nrelocs, s->name); + } +#endif + + s->flags |= IMAGE_SCN_LNK_NRELOC_OVFL; + s->nrelocs++; +} + static void coff_write(void) { int32_t pos, sympos, vsize; @@ -860,13 +879,15 @@ static void coff_write(void) } /* - * Work out how big the file will get. Calculate the start of - * the `real' symbols at the same time. + * Work out how big the file will get. + * Calculate the start of the `real' symbols at the same time. + * Check for massive relocations. */ pos = 0x14 + 0x28 * nsects; initsym = 3; /* two for the file, one absolute */ for (i = 0; i < nsects; i++) { if (sects[i]->data) { + coff_adjust_relocs(sects[i]); sects[i]->pos = pos; pos += sects[i]->len; sects[i]->relpos = pos; @@ -939,7 +960,18 @@ static void coff_section_header(char *name, int32_t vsize, fwriteint32_t(datapos, ofile); fwriteint32_t(relpos, ofile); fwriteint32_t(0L, ofile); /* no line numbers - we don't do 'em */ - fwriteint16_t(nrelocs, ofile); + + /* + * a special case -- if there are too many relocs + * we have to put IMAGE_SCN_MAX_RELOC here and write + * the real relocs number into VirtualAddress of first + * relocation + */ + if (flags & IMAGE_SCN_LNK_NRELOC_OVFL) + fwriteint16_t(IMAGE_SCN_MAX_RELOC, ofile); + else + fwriteint16_t(nrelocs, ofile); + fwriteint16_t(0, ofile); /* again, no line numbers */ fwriteint32_t(flags, ofile); } @@ -948,6 +980,13 @@ static void coff_write_relocs(struct Section *s) { struct Reloc *r; + /* a real number of relocations if needed */ + if (s->flags & IMAGE_SCN_LNK_NRELOC_OVFL) { + fwriteint32_t(s->nrelocs, ofile); + fwriteint32_t(0, ofile); + fwriteint16_t(0, ofile); + } + for (r = s->head; r; r = r->next) { fwriteint32_t(r->address, ofile); fwriteint32_t(r->symbol + (r->symbase == REAL_SYMBOLS ? initsym : diff --git a/output/pecoff.h b/output/pecoff.h index 7c90c49c..924ccd8e 100644 --- a/output/pecoff.h +++ b/output/pecoff.h @@ -137,6 +137,8 @@ #define IMAGE_SCN_LNK_REMOVE 0x00000800 #define IMAGE_SCN_LNK_COMDAT 0x00001000 +#define IMAGE_SCN_MAX_RELOC 0xffff + #define IMAGE_SCN_MEM_FARDATA 0x00008000 #define IMAGE_SCN_MEM_PURGEABLE 0x00020000 #define IMAGE_SCN_MEM_16BIT 0x00020000 -- cgit v1.2.1