0
votes

Assembling the x86 assembly code produced by my compiler using the version of GNU Assembler that comes with MinGW-w64 produces the following warning:

E:/MinGW32/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: analogClockForWindows.exe: warning: section .bss: alignment 2**32 not representable

What does that mean? What puzzles me the most is that the assembly code does not mention .bss at all.
I do not know if it is related, but the version of GNU Assembler that comes with CygWin and one that comes with TDM-GCC both refuse to even assemble my code, and give a ton of error messages.
The assembly code that is produced by my compiler is available here: https://github.com/FlatAssembler/ArithmeticExpressionCompiler/files/6446315/analogClockForWindows.s.zip

EDIT: I was simply using gcc -o analogClockForWindows analogClockForWindows.s to compile the assembly code produced by my compiler.

UPDATE: I think this is the minimal example that triggers that warning:

.text
.comm   output,7360,32
.global _main
_main:
movl    $0, %eax
ret
2
It probably means that you used .align 32, and it was interpreted as .p2align (power-of-2) instead of .balign (byte). Never use the ambiguous .align directive. I'm not interested enough to download and unzip code to look at it, if you can't be bothered to put a minimal reproducible example into the question. - Peter Cordes
Also, that's an ld error, not as. So your code does assemble, but then ld chokes on the .obj created by GAS? Probably worth looking at the .obj with some tools like a PE/COFF equivalent of readelf. - Peter Cordes
You shouldn't even need global variables for evaluating an expression. Just reserve some stack space if you run out of x87 stack registers. Or I guess you're taking input from global vars instead of stack args or register args :/ - Peter Cordes
Pretty obviously for the same reason as .align: the 3rd arg is treated as a power-of-2 alignment on this target, but as a byte value for x86-elf-linux. - Peter Cordes
Ah, I see. Then probably it ignores the requested alignment and you get some default, maybe 4, 8, or 16 bytes. - Peter Cordes

2 Answers

4
votes

https://sourceware.org/binutils/docs/as/Comm.html#Comm

When using ELF or (as a GNU extension) PE, the .comm directive takes an optional third argument. This is the desired alignment of the symbol, specified for ELF as a byte boundary (for example, an alignment of 16 means that the least significant 4 bits of the address should be zero), and for PE as a power of two (for example, an alignment of 5 means aligned to a 32-byte boundary).

ELF is the executable format used on Linux, and PE is on Windows. So for ELF (Linux), .comm output,7360,32 requests that output be aligned to a 32-byte boundary, which is fine. But for PE (Windows), the same directive is interpreted as asking for 2**32 byte alignment, which is impossible. On Windows you should instead write .comm output,7360,5.

I don't know why these are different; probably for compatibility with other different assemblers.

You'll probably need to add a flag to your compiler to select between Windows and Linux so that the correct directive can be output for each case.

3
votes

It could mean that you used .align 32, and it was interpreted as .p2align (power-of-2) instead of .balign (byte).

Never use the ambiguous .align directive when targeting GAS, which supports unambiguous directives.


In your case, the alignment is coming in the 3rd arg to .comm to define a global variable in the BSS. Like .align, the interpretation is target-dependent, and when assembling for Windows, that means you're asking it to align by 2**32 (or 4GiB), which ld doesn't handle.

(When assembling for i386-elf-linux, it means align by 32, 2**5, which works as intended.)

As documented in the GAS manual:

When using ELF or (as a GNU extension) PE, the .comm directive takes an optional third argument. This is the desired alignment of the symbol, specified for ELF as a byte boundary (for example, an alignment of 16 means that the least significant 4 bits of the address should be zero), and for PE as a power of two (for example, an alignment of 5 means aligned to a 32-byte boundary).

The alignment must be an absolute expression, and it must be a power of two. If ld allocates uninitialized memory for the common symbol, it will use the alignment when placing the symbol.

If no alignment is specified, as will set the alignment to the largest power of two less than or equal to the size of the symbol, up to a maximum of 16 on ELF, or the default section alignment of 4 on PE

Unfortunately there's no portable unambiguous syntax way to use it. You could just omit that optional 3rd arg and use the default alignment.

Or you could instead use a .bss directive to switch to the BSS section and use .space to reserve space after a label:.

Or just don't use any global vars, and leave the result in st0. You don't need any to eval an expression, if you take args on the stack instead of globals. At most you could use stack space, if you run out of x87 registers. Or you could reference globals but leave the definitions up to other compilation units (e.g. a caller that does input/output.)

Also, does result really need to be 7360 bytes? Your compiler (https://flatassembler.github.io/compiler.html) only ever uses [result], not [result + reg] or + constant