Search code examples
assemblyelfmemory-alignmentgnu-assembler

How to specify ELF section alignment in GNU as?


I'm trying to use GNU as as a generic assembler similar in use as nasm. I make a template source like this:

.section .text
.globl _start
.intel_syntax noprefix
_start:
call 0xb77431c0 # the instruction I want to assemble

And then I run the assemble command like this:

as --32 -o test.o test.s
ld -m elf_i386 -Ttext 0xb77431d9 --oformat binary -o test.bin test.o

All works well with binutils 2.24. But it appears that as from binutils 2.22 (the one in Ubuntu Precise) aligns .text section to the 4-byte boundary, thus instead of the expected disassembly I get wrong results:

 # expected and working in binutils 2.24
$ ndisasm -b 32 -o 0xb77431d9 test.bin
B77431D9  E8E2FFFFFF        call dword 0xb77431c0

 # actual in binutils 2.22
$ ndisasm -b 32 -o 0xb77431d9 test.bin
B77431D9  90                nop
B77431DA  90                nop
B77431DB  90                nop
B77431DC  E8DFFFFFFF        call dword 0xb77431c0

The problem is in the as command (i.e. not ld): readelf -S gives me the following for results of as 2.22:

$ readelf -S test.o | grep ' \.text'
  [ 1] .text             PROGBITS        00000000 000034 000005 00  AX  0   0  4

And for 2.24 I have

$ readelf -S test.o | grep ' \.text'
  [ 1] .text             PROGBITS        00000000 000034 000005 00  AX  0   0  1

So the problem is indeed alignment of .text section. I've tried placing .align 0 and .align 1 in various places in the source, but it didn't change the output.

So my question now: how to explicitly specify section alignment for ELF target in GNU assembler?


Solution

  • Likely the default linker script LD is causing some kind of forced alignment. I'd create a basic linker script with the origin point, and tell it which sections you want (specifying the alignment), and in what order sections will appear.

    linker.ld

    SECTIONS
    {
        . = 0xb77431d9;
        .text . : SUBALIGN(0)
        {
            *(.text)
        }
    }
    

    This script utilizes the SUBALIGN directive to override the alignment of the .text section as it appears in the input object. From the GNU Linker documentation it has this effect:

    3.6.8.4 Forced Input Alignment

    You can force input section alignment within an output section by using SUBALIGN. The value specified overrides any alignment given by input sections, whether larger or smaller.

    Then use:

    as --32 -o test.o test.s
    ld -T linker.ld -m elf_i386 --oformat binary -o test.bin test.o
    

    The output I get here is:

    ndisasm -b 32 -o 0xb77431d9 test.bin
    B77431D9  E8E2FFFFFF        call dword 0xb77431c0
    

    When a section in an object file(s) doesn't get processed by the sections in the linker script, the input sections will still be emitted. All unprocessed input sections will be output at the end in the order they were encountered by the linker.