summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin (Intel) <hpa@zytor.com>2020-07-10 18:14:09 -0700
committerH. Peter Anvin (Intel) <hpa@zytor.com>2020-07-10 18:14:09 -0700
commitbaaa5ca4413e7ac73fe98e682be13f2da529e2cf (patch)
tree4445557dd0f5eb0469fcb1c62fda0ad026a615d0
parentbb3156533b9baf836b746c638111fca82c65f98a (diff)
downloadnasm-baaa5ca4413e7ac73fe98e682be13f2da529e2cf.tar.gz
outcoff: don't drop align= option alone on a section line
If the section/segment directive *only* contained an align= directive, it would get lost. Fix that. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
-rw-r--r--output/outcoff.c68
1 files changed, 39 insertions, 29 deletions
diff --git a/output/outcoff.c b/output/outcoff.c
index de22fb88..bcd9ff3f 100644
--- a/output/outcoff.c
+++ b/output/outcoff.c
@@ -72,11 +72,11 @@
* (2) Win32 doesn't bother putting any flags in the header flags
* field (at offset 0x12 into the file).
*
- * (3) Win32 uses some extra flags into the section header table:
+ * (3) Win32/64 uses some extra flags into the section header table:
* it defines flags 0x80000000 (writable), 0x40000000 (readable)
* and 0x20000000 (executable), and uses them in the expected
- * combinations. It also defines 0x00100000 through 0x00700000 for
- * section alignments of 1 through 64 bytes.
+ * combinations. It also defines 0x00100000 through 0x00f00000 for
+ * section alignments of 1 through 8192 bytes.
*
* (4) Both standard COFF and Win32 COFF seem to use the DWORD
* field directly after the section name in the section header
@@ -285,14 +285,22 @@ int coff_make_section(char *name, uint32_t flags)
return coff_nsects - 1;
}
+/*
+ * Convert an alignment value to the corresponding flags.
+ * An alignment value of 0 means no flags should be set.
+ */
static inline uint32_t coff_sectalign_flags(unsigned int align)
{
- return (ilog2_32(align) + 1) << 20;
+ return (alignlog2_32(align) + 1) << 20;
}
+/*
+ * Get the alignment value from a flags field.
+ * Returns 0 if no alignment defined.
+ */
static inline unsigned int coff_alignment(uint32_t flags)
{
- return 1U << (((flags & IMAGE_SCN_ALIGN_MASK) >> 20) - 1);
+ return (1U << ((flags & IMAGE_SCN_ALIGN_MASK) >> 20)) >> 1;
}
static int32_t coff_section_names(char *name, int *bits)
@@ -364,10 +372,13 @@ static int32_t coff_section_names(char *name, int *bits)
nasm_nonfatal("argument to `align' is not numeric");
else {
unsigned int align = atoi(q + 6);
- if (!align || ((align - 1) & align)) {
+ /* Allow align=0 meaning use default */
+ if (!align) {
+ align_flags = 0;
+ } else if (!is_power2(align)) {
nasm_nonfatal("argument to `align' is not a"
" power of two");
- } else if (align > 8192) {
+ } else if (align > COFF_MAX_ALIGNMENT) {
nasm_nonfatal("maximum alignment in COFF is %d bytes",
COFF_MAX_ALIGNMENT);
} else {
@@ -382,30 +393,31 @@ static int32_t coff_section_names(char *name, int *bits)
break;
if (i == coff_nsects) {
if (!flags) {
- if (!strcmp(name, ".data"))
+ flags = TEXT_FLAGS;
+
+ if (!strcmp(name, ".data")) {
flags = DATA_FLAGS;
- else if (!strcmp(name, ".rdata"))
+ } else if (!strcmp(name, ".rdata")) {
flags = RDATA_FLAGS;
- else if (!strcmp(name, ".bss"))
+ } else if (!strcmp(name, ".bss")) {
flags = BSS_FLAGS;
- else if (win64 && !strcmp(name, ".pdata"))
- flags = PDATA_FLAGS;
- else if (win64 && !strcmp(name, ".xdata"))
- flags = XDATA_FLAGS;
- else
- flags = TEXT_FLAGS;
+ } else if (win64) {
+ if (!strcmp(name, ".pdata"))
+ flags = PDATA_FLAGS;
+ else if (!strcmp(name, ".xdata"))
+ flags = XDATA_FLAGS;
+ }
}
i = coff_make_section(name, flags);
- if (flags)
- coff_sects[i]->flags = flags;
- } else if (flags) {
- /* Check if any flags are respecified */
-
- /* Warn if non-alignment flags differ */
- if ((flags ^ coff_sects[i]->flags) & ~IMAGE_SCN_ALIGN_MASK &&
- coff_sects[i]->pass_last_seen == pass_count()) {
- nasm_warn(WARN_OTHER, "section attributes changed on"
- " redeclaration of section `%s'", name);
+ coff_sects[i]->align_flags = align_flags;
+ } else {
+ if (flags) {
+ /* Warn if non-alignment flags differ */
+ if (((flags ^ coff_sects[i]->flags) & ~IMAGE_SCN_ALIGN_MASK) &&
+ coff_sects[i]->pass_last_seen == pass_count()) {
+ nasm_warn(WARN_OTHER, "section attributes changed on"
+ " redeclaration of section `%s'", name);
+ }
}
/* Check if alignment might be needed */
@@ -419,6 +431,7 @@ static int32_t coff_section_names(char *name, int *bits)
if (align_flags > sect_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) {
@@ -428,9 +441,6 @@ static int32_t coff_section_names(char *name, int *bits)
nasm_assert(padding <= sizeof buffer);
- if (pass_final())
- nasm_nonfatal("section alignment changed during code generation");
-
if (coff_sects[i]->flags & IMAGE_SCN_CNT_CODE) {
/* Fill with INT 3 instructions */
memset(buffer, 0xCC, padding);