[nasm:nasm-2.15.xx] BR 3392692: outcoff: allow user to reduce the default alignment

nasm-bot for H. Peter Anvin (Intel) hpa at zytor.com
Mon Jul 6 21:51:04 PDT 2020


Commit-ID:  cd8743142496c29cffbec84501f34416d00a6b33
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=cd8743142496c29cffbec84501f34416d00a6b33
Author:     H. Peter Anvin (Intel) <hpa at zytor.com>
AuthorDate: Mon, 6 Jul 2020 21:46:43 -0700
Committer:  H. Peter Anvin (Intel) <hpa at zytor.com>
CommitDate: Mon, 6 Jul 2020 21:46:43 -0700

BR 3392692: outcoff: allow user to reduce the default alignment

NASM would incorrectly only allow for the alignment to be increased,
even when overridden by the user. Allow the user to specify any
alignment value and have it override the partition type default.

The user can increade their own alignment value specification later,
of course, and the sectalign directive will present a floor for either
kind of specification.

Reported-by: Dale Curtis <dalecurtis at chromium.org>
Signed-off-by: H. Peter Anvin (Intel) <hpa at zytor.com>


---
 doc/nasmdoc.src  |  5 +++
 output/outcoff.c | 93 ++++++++++++++++++++++++++++++++++----------------------
 output/pecoff.h  |  4 ++-
 3 files changed, 65 insertions(+), 37 deletions(-)

diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src
index eb49d1a8..62a70d57 100644
--- a/doc/nasmdoc.src
+++ b/doc/nasmdoc.src
@@ -5765,6 +5765,11 @@ qualifiers are:
 \c section .rdata   rdata align=8
 \c section .bss     bss   align=4
 
+The \c{win64} format also adds:
+
+\c section .pdata   rdata align=4
+\c section .xdata   rdata align=8
+
 Any other section name is treated by default like \c{.text}.
 
 \S{win32safeseh} \c{win32}: Safe Structured Exception Handling
diff --git a/output/outcoff.c b/output/outcoff.c
index 60b7fdf8..de22fb88 100644
--- a/output/outcoff.c
+++ b/output/outcoff.c
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 1996-2017 The NASM Authors - All Rights Reserved
+ *   Copyright 1996-2020 The NASM Authors - All Rights Reserved
  *   See the file AUTHORS included with the NASM distribution for
  *   the specific copyright holders.
  *
@@ -158,6 +158,8 @@ static int32_t imagebase_sect;
 #define BSS_FLAGS       ((win32 | win64) ? BSS_FLAGS_WIN   : BSS_FLAGS_DOS)
 #define RDATA_FLAGS     ((win32 | win64) ? RDATA_FLAGS_WIN : RDATA_FLAGS_DOS)
 
+#define COFF_MAX_ALIGNMENT 8192
+
 #define SECT_DELTA 32
 struct coff_Section **coff_sects;
 static int sectlen;
@@ -283,15 +285,20 @@ int coff_make_section(char *name, uint32_t flags)
     return coff_nsects - 1;
 }
 
-static inline int32_t coff_sectalign_flags(unsigned int align)
+static inline uint32_t coff_sectalign_flags(unsigned int align)
 {
     return (ilog2_32(align) + 1) << 20;
 }
 
+static inline unsigned int coff_alignment(uint32_t flags)
+{
+    return 1U << (((flags & IMAGE_SCN_ALIGN_MASK) >> 20) - 1);
+}
+
 static int32_t coff_section_names(char *name, int *bits)
 {
     char *p;
-    uint32_t flags, align_and = ~0L, align_or = 0L;
+    uint32_t flags, align_flags;
     int i;
 
     /*
@@ -317,7 +324,7 @@ static int32_t coff_section_names(char *name, int *bits)
             name[8] = '\0';
         }
     }
-    flags = 0;
+    flags = align_flags = 0;
 
     while (*p && nasm_isspace(*p))
         p++;
@@ -353,24 +360,18 @@ static int32_t coff_section_names(char *name, int *bits)
                               " informational sections");
             }
         } else if (!nasm_strnicmp(q, "align=", 6)) {
-            if (!(win32 | win64))
-                nasm_nonfatal("standard COFF does not support"
-                              " section alignment specification");
+            if (q[6 + strspn(q + 6, "0123456789")])
+                nasm_nonfatal("argument to `align' is not numeric");
             else {
-                if (q[6 + strspn(q + 6, "0123456789")])
-                    nasm_nonfatal("argument to `align' is not numeric");
-                else {
-                    unsigned int align = atoi(q + 6);
-                    if (!align || ((align - 1) & align))
-                        nasm_nonfatal("argument to `align' is not a"
-                                      " power of two");
-                    else if (align > 64)
-                        nasm_nonfatal("Win32 cannot align sections"
-                                      " to better than 64-byte boundaries");
-                    else {
-                        align_and = ~0x00F00000L;
-                        align_or  = coff_sectalign_flags(align);
-                    }
+                unsigned int align = atoi(q + 6);
+                if (!align || ((align - 1) & align)) {
+                    nasm_nonfatal("argument to `align' is not a"
+                                  " power of two");
+                } else if (align > 8192) {
+                    nasm_nonfatal("maximum alignment in COFF is %d bytes",
+                                  COFF_MAX_ALIGNMENT);
+                } else {
+                    align_flags = coff_sectalign_flags(align);
                 }
             }
         }
@@ -397,11 +398,8 @@ static int32_t coff_section_names(char *name, int *bits)
         i = coff_make_section(name, flags);
         if (flags)
             coff_sects[i]->flags = flags;
-        coff_sects[i]->flags &= align_and;
-        coff_sects[i]->flags |= align_or;
     } else if (flags) {
         /* Check if any flags are respecified */
-        unsigned int align_flags = flags & IMAGE_SCN_ALIGN_MASK;
 
         /* Warn if non-alignment flags differ */
         if ((flags ^ coff_sects[i]->flags) & ~IMAGE_SCN_ALIGN_MASK &&
@@ -409,18 +407,20 @@ static int32_t coff_section_names(char *name, int *bits)
             nasm_warn(WARN_OTHER, "section attributes changed on"
                       " redeclaration of section `%s'", name);
         }
+
         /* Check if alignment might be needed */
-        if (align_flags > IMAGE_SCN_ALIGN_1BYTES) {
-            unsigned int sect_align_flags = coff_sects[i]->flags & IMAGE_SCN_ALIGN_MASK;
+        if (align_flags) {
+            uint32_t sect_align_flags = coff_sects[i]->align_flags;
 
             /* Compute the actual alignment */
-            unsigned int align = 1u << ((align_flags - IMAGE_SCN_ALIGN_1BYTES) >> 20);
+            unsigned int align = coff_alignment(align_flags);
 
             /* Update section header as needed */
             if (align_flags > sect_align_flags) {
-                coff_sects[i]->flags = (coff_sects[i]->flags & ~IMAGE_SCN_ALIGN_MASK) | align_flags;
+                coff_sects[i]->align_flags = align_flags;
             }
             /* Check if not already aligned */
+            /* XXX: other formats don't do this... */
             if (coff_sects[i]->len % align) {
                 unsigned int padding = (align - coff_sects[i]->len) % align;
                 /* We need to write at most 8095 bytes */
@@ -875,6 +875,28 @@ static inline void coff_adjust_relocs(struct coff_Section *s)
     s->nrelocs++;
 }
 
+/*
+ * Make sure we satisfy all section alignment requirements and put the
+ * resulting alignment flags into the flags value in the header.  If
+ * no user-specified alignment is given, use the default for the
+ * section type; then either way round up to alignment specified by
+ * sectalign directives.
+ */
+static inline void coff_adjust_alignment(struct coff_Section *s)
+{
+    uint32_t align_flags = s->align_flags;
+
+    if (!align_flags) {
+        /* No user-specified alignment, use default for partition type */
+        align_flags = s->flags & IMAGE_SCN_ALIGN_MASK;
+    }
+
+    if (align_flags < s->sectalign_flags)
+        align_flags = s->sectalign_flags;
+
+    s->flags = (s->flags & ~IMAGE_SCN_ALIGN_MASK) | align_flags;
+}
+
 static void coff_write(void)
 {
     int32_t pos, sympos, vsize;
@@ -905,6 +927,7 @@ static void coff_write(void)
     pos = 0x14 + 0x28 * coff_nsects;
     initsym = 3;                /* two for the file, one absolute */
     for (i = 0; i < coff_nsects; i++) {
+        coff_adjust_alignment(coff_sects[i]);
         if (coff_sects[i]->data) {
             coff_adjust_relocs(coff_sects[i]);
             coff_sects[i]->pos = pos;
@@ -1104,7 +1127,7 @@ static void coff_write_symbols(void)
 static void coff_sectalign(int32_t seg, unsigned int value)
 {
     struct coff_Section *s = NULL;
-    uint32_t align;
+    uint32_t flags;
     int i;
 
     for (i = 0; i < coff_nsects; i++) {
@@ -1117,14 +1140,12 @@ static void coff_sectalign(int32_t seg, unsigned int value)
     if (!s || !is_power2(value))
         return;
 
-    /* DOS has limitation on 64 bytes */
-    if (!(win32 | win64) && value > 64)
-        return;
+    if (value > COFF_MAX_ALIGNMENT)
+        value = COFF_MAX_ALIGNMENT; /* Do our best... */
 
-    align = (s->flags & IMAGE_SCN_ALIGN_MASK);
-    value = coff_sectalign_flags(value);
-    if (value > align)
-        s->flags = (s->flags & ~IMAGE_SCN_ALIGN_MASK) | value;
+    flags = coff_sectalign_flags(value);
+    if (flags > s->sectalign_flags)
+        s->sectalign_flags = flags;
 }
 
 extern macros_t coff_stdmac[];
diff --git a/output/pecoff.h b/output/pecoff.h
index 7b6f46c2..efecd0f9 100644
--- a/output/pecoff.h
+++ b/output/pecoff.h
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 1996-2010 The NASM Authors - All Rights Reserved
+ *   Copyright 1996-2020 The NASM Authors - All Rights Reserved
  *   See the file AUTHORS included with the NASM distribution for
  *   the specific copyright holders.
  *
@@ -481,6 +481,8 @@ struct coff_Section {
     int32_t index;
     struct coff_Reloc *head, **tail;
     uint32_t flags;             /* section flags */
+    uint32_t align_flags;       /* user-specified alignment flags */
+    uint32_t sectalign_flags;   /* minimum alignment from sectalign */
     char *name;
     int32_t namepos;            /* Offset of name into the strings table */
     int32_t pos, relpos;


More information about the Nasm-commits mailing list