Search code examples
arraysassemblynasmmasmsizeof

`TYPE` but then in NASM


I know there are SIZEOF and TYPE in MASM, but what about NASM? As I found, it doesn't have these.

For example:

array   dw 1d, 2d, 3d, 4d
arrSize db $-array         ;4 elements * 2 bytes (size of one element) = 8 bytes

This is how I can make alternative of SIZEOF array in NASM. If I want the number of array elements, I can divide arrSize by 2 (if array elements are words). But if array elements are double words (32-bit), I need to divide by 4.

Is there an alternative for TYPE from MASM in NASM? If not, how can I make the program determine the size of the element itself?


Solution

  • NASM keeps its directives simple and with minimal automagic features.
    It doesn't seem to be corresponding directives for the MASM type, sizeof and length operators.
    Luckily, NASM took a much better approach than introducing heavy typing in assembly: it developed a very rich and expressive macro system.

    Consider this simple macro:

    ;array <label>, <item directive>, <items>
    %macro array 4-*
        %1: %2 %{3}                         ;label: db/dw/dd/... <firstItem>    
        %%second: %2 %{4:-1}                ;Local label (to get item size) and rest of the items
        
        %1_size EQU $ - %1                  ;Size of the array in bytes (here - label)
        %1_type EQU %%second - %1           ;Size of an item in bytes (second - label)
        %1_lengthof EQU %1_size / %1_type   ;Number of items (size of array /  size of item)
    %endmacro
    

    You can use it like array my_array, dd, 1, 2, 3. Not exactly like my_array dd 1, 2, 3 but close.
    Then you have:

    • my_array_size. Size of the array in bytes.
    • my_array_type. Size of one array item in bytes.
    • my_array_lengthof. Number of items in the array.

    You can tweak the macro to adapt it to your personal style (eg: to generate my_array.size and similar or make arrdb, arrdw, arrdd variants that implicitly take the item declaration directive).

    Example:

    BITS 32
    
    ;array <label>, <item directive>, <items>
    %macro array 4-*
        %1: %2 %{3}             ;label: db/dw/dd/... <firstItem>    
        %%second: %2 %{4:-1}            ;Local label, to get item size
        
        %1_size EQU $ - %1          ;Size of the array in bytes (here - label)
        %1_type EQU %%second - %1       ;Size of an item in bytes (second - label)
        %1_lengthof EQU %1_size / %1_type   ;Number of items (size of array /  size of item)
    %endmacro
    
    
    ;To test, use ndisam -b32
    mov eax, my_array_size
    mov eax, my_array_type
    mov eax, my_array_lengthof
    mov eax, DWORD [my_array]
    
    
    ;The array (ignore on output from ndisasm)
    array my_array, dd, 1, 2, 3
    

    Using ndisam -b32 on the generated binary:

    00000000  B80C000000        mov eax,0xc
    00000005  B804000000        mov eax,0x4
    0000000A  B803000000        mov eax,0x3
    0000000F  A114000000        mov eax,[0x14]
    00000014  <REDACTED GARBAGE>