Search code examples
assemblygccx86attgnu-assembler

Stack address size on 80486, using gcc


GCC manual says that -m32 "generates code that runs on any i386 system". Assume I want to write a function that swaps the bytes of a 32 bit number:

    .text
    .globl  SwapBytes
    .type   SwapBytes, @function
SwapBytes:
    pushl %ebp
    movl %esp, %ebp
    movl 8(%ebp), %eax
    bswapl %eax
    popl %ebp
    ret

However, the BSWAP instruction is not supported on 80386, only since 80486. So I assemble gcc SwapBytes.s -march=i486 -c -o SwapBytes.elf, as suggested by the cited manual. But then I get an error:

Assembler messages:
Error: invalid instruction suffix for `push'
Error: invalid instruction suffix for `pop'

But why? I thought, 32 bit stack was introduced with 80386. Ok, let's try with -march=pentium3 in case I missed something about 32 bit stack, but the same result. However, if I assemble just with the -m32 option, gcc does not complain.

I thought maybe gcc ignores the -march=... options when assembling (and assumes -m64?), but does not ignore the -m32 option? But what options can I use to specify the CPU I want to assemble for?


Solution

  • It appears that gcc passes the -m32 and -m64 options to the assembler (translating them to --32 and --64), but it does not pass along the -march= options. I think this is because the assembler recognizes a different set of architectures than the compiler does. For instance, -march=skylake is accepted by gcc but would be an error to the assembler.

    But you can pass it explicitly using the -Wa option. So for instance gcc -m32 -Wa,-march=i386 bswap.s will give

    Error: `bswap' is not supported on `i386'
    

    and gcc -m32 -Wa,-march=i486 bswap.s will run successfully.

    Note that the default architecture depends on how you configured your binutils installation. But it is most likely something much more modern than i386, which is why the assembler doesn't complain when you use bswap without an -march option.