summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrill Gorcunov <gorcunov@gmail.com>2010-11-20 14:18:23 +0300
committerCyrill Gorcunov <gorcunov@gmail.com>2010-11-20 14:18:23 +0300
commitcb9a459560068aa96481a3c424a97cd6d84d9061 (patch)
tree96a22c194db905af884b888c8638112b8c8f82d8
parent3cb0e8c052a672424eaf59a021f0dbfb6ef205b8 (diff)
downloadnasm-cb9a459560068aa96481a3c424a97cd6d84d9061.tar.gz
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>
-rw-r--r--output/outcoff.c45
-rw-r--r--output/pecoff.h2
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