diff options
author | Cyrill Gorcunov <gorcunov@gmail.com> | 2010-11-20 14:18:23 +0300 |
---|---|---|
committer | Cyrill Gorcunov <gorcunov@gmail.com> | 2010-11-20 14:18:23 +0300 |
commit | cb9a459560068aa96481a3c424a97cd6d84d9061 (patch) | |
tree | 96a22c194db905af884b888c8638112b8c8f82d8 /output | |
parent | 3cb0e8c052a672424eaf59a021f0dbfb6ef205b8 (diff) | |
download | nasm-cb9a459560068aa96481a3c424a97cd6d84d9061.tar.gz nasm-cb9a459560068aa96481a3c424a97cd6d84d9061.tar.bz2 nasm-cb9a459560068aa96481a3c424a97cd6d84d9061.zip |
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 <gorcunov@gmail.com>
Diffstat (limited to 'output')
-rw-r--r-- | output/outcoff.c | 45 | ||||
-rw-r--r-- | output/pecoff.h | 2 |
2 files changed, 44 insertions, 3 deletions
diff --git a/output/outcoff.c b/output/outcoff.c index 5b232bb..5c1de01 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 7c90c49..924ccd8 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 |