BeeOnRope
BeeOnRope

Reputation: 64905

Aligning a given instruction, but putting the alignment padding somewhere other than immediately before the instruction

Is it possible, in nasm (and by extension, yasm) to write a macro or otherwise use pre-processor features to align some particular instruction to a given power of two (or possible a given power of two plus some offset), but inserting the alignment padding not immediately before the instruction, but at some arbitrary earlier place?

For example, imagine you had a function where you wanted to align the top of a loop inside the function by 32, you could do it like this:

function:
  xor eax, eax
  mov ecx, 1
ALIGN 32
.top:
  add eax, ecx
  inc ecx
  cmp ecx, rdi
  jne .top

This will a bunch of nop instructions at the point of the ALIGN 32 directive, which will be executed before entry to the loop (or you could jump over them, but this still executes something in order to jump over the padding.

What you didn't want to add padding inside the function itself, but rather before the function where it will never be executed. For example, if there are 10 bytes before the loop entry, aligning the top of the function to 32N - 10 would do it. Like so:

padding_magic .top 32
function:
  xor eax, eax
  mov ecx, 1
ALIGN 32
.top:
  add eax, ecx
  inc ecx
  cmp ecx, rdi
  jne .top

Is there some way to accomplish it in nasm, i.e., implement padding_magic?

Upvotes: 3

Views: 409

Answers (1)

Ross Ridge
Ross Ridge

Reputation: 39581

Ok, I managed to figure out a not too hacky way of doing this. The trick is to assemble the alignment padding after the function and rely segment ordering to put everything in the correct order.

%macro BEGIN_PADDED_FUNC 0-1 16
%define _func_name %00
%define _align %1
%define _section_base .text.%[_func_name].

        [SECTION %[_section_base]1 progbits alloc exec nowrite align=_align]
        [SECTION %[_section_base]2 progbits alloc exec nowrite align=1]

_func_name:
%endmacro

%macro ALIGN_PADDED_FUNC 0
%[_func_name].align_point:
%endmacro

%macro END_PADDED_FUNC 0
        [SECTION %[_section_base]1]
        TIMES ((_align - (%[_func_name].align_point - _func_name) % _align) \
               % _align) nop
        __SECT__
%endmacro

The above macros would be used like this:

function BEGIN_PADDED_FUNC 32
        xor     eax, eax
        mov     ecx, 1

        ALIGN_PADDED_FUNC
.top:
        add     eax, ecx
        inc     ecx
        cmp     ecx, edi
        jne     .top

        END_PADDED_FUNC

This code assumes ELF and a reasonable linker and/or linker script that will put a section named .text.function.1 before .text.function.2 if that's the order they first appear in the object file. It can probably be modified to work with PECOFF, but I haven't tried this. I've only tested this with NASM, I have no clue whether this would work in YASM.

Upvotes: 4

Related Questions