assemblylinkernasmx86-16dos

Getting nasm -f obj and WarpLink to emit alignment for an empty last section


I'm trying to use NASM (version 2.16.02rc2) with its -f obj (OMF) output format and my version of WarpLink (wl.exe in the 2024-08-01 current build, renamed to warplink.exe, from the most recent revision in this repo) to assemble a DOS MZ executable.

However, it appears that this combination of assembler and linker lead to deleting "uninitialised" (nobits) space at the end of the executable image. I don't want this in this case because I want to add a section ("LAST") that only causes the end of the (initialised) image to be aligned on a paragraph (= 16 byte) boundary. Unfortunately if I just add the section as in section LAST align=16 it appears that albeit the section is aligned, its alignment data is considered uninitialised and deleted from the actual executable image.

In the below test case I used x2b2.com (from the 2024-11-20 current release from the most recent revision in this repo) to extract the executable image from the MZ .exe file and rather than the expected 16 bytes it is only 3 bytes in size.

test.asm source:


        section START align=1
        nop
        nop
        nop

        section LAST align=16

group GROUP START LAST

mak.sh source, using NASM, dosemu2, WarpLink, and x2b2:

#! /bin/bash

nasm -fobj test.asm -l test.lst -o test.obj
dosemu -dumb -quiet -q -K "$PWD" -E "warplink /mx test.obj,test.exe,test.map;"
dosemu -dumb -quiet -q -K "$PWD" -E "x2b2 test.exe test.bin"

Running the test case:

20241205$ cat test.asm

        section START align=1
        nop
        nop
        nop

        section LAST align=16

group GROUP START LAST
20241205$ cat mak.sh
#! /bin/bash

nasm -fobj test.asm -l test.lst -o test.obj
dosemu -dumb -quiet -q -K "$PWD" -E "warplink /mx test.obj,test.exe,test.map;"
dosemu -dumb -quiet -q -K "$PWD" -E "x2b2 test.exe test.bin"
20241205$ ./mak.sh
About to Execute : warplink /mx test.obj,test.exe,test.map;

WarpLink release 0 by ecm (2024 August), Michael Devore (1989-1993).
Public Domain software, all copyrights surrendered.

Warning in TEST.EXE
  Problem:  No stack segment was found for the EXE file.
  Solution: This is possibly an error in your program.
            An EXE file, unlike a COM file, must internally setup
            its own stack if it has no stack segment.  To create a
            COM file, use the /c option of WarpLink.


Total number of warnings: 1

EXE load image size: 001K
About to Execute : x2b2 test.exe test.bin
X2B2 ecm release 1  -  Public Domain Software by Henry T. Nettles
Input File ==> "test.exe"  Output File ==> "test.bin"
Code Size = 3           Code Start = 512         Initial IP = 0
Size of output file = 3
20241205$

test.map result:


PROGRAM: TEST.EXE
DATE:    12/05/24
TIME:    02:51 pm

Start  Stop   Length Name                   Class
00000H 00002H 00003H START                  
00010H 00010H 00000H LAST                   

Origin   Group
0000:0   GROUP

Detailed Segment Map
Name             Ovl# Address   Length Align Combine Class    Group     Module       File
START                 0000:0000  0003h BYTE  PUBLIC           GROUP     TEST.ASM     TEST.OBJ
LAST                  0001:0000  0000h PARA  PUBLIC           GROUP     TEST.ASM     TEST.OBJ

 Address   Status   Symbol Name

Program entry point at 0000:0000

Is there a way to emit the alignment, but no further initialised data in the LAST section?


Edited to add: Jester suggested in a comment:

Does it have to be a section? Wouldn't adding an align 16 at the end of your code work for you?

It has to be a section because there may actually be any number of "mid" sections and I don't want to set align=16 for any of the mid sections. Using align 16 at the end of a section (here: the last of the mid sections) will either do sectalign (forcing that mid section to have an alignment of 16) or if we sectalign off then the align 16 will only operate in the (unaligned) mid section and not align to the whole image boundary. Here's two more examples showing this:

20241205$ cat test2.asm

        section START align=1
        nop
        nop
        nop

        section MID align=1
        ds
        es
        ss
        cs

        align 16

group GROUP START MID
20241205$ ./mak2.sh
About to Execute : warplink /mx test2.obj,test2.exe,test2.map;

WarpLink release 0 by ecm (2024 August), Michael Devore (1989-1993).
Public Domain software, all copyrights surrendered.

Warning in TEST2.EXE
  Problem:  No stack segment was found for the EXE file.
  Solution: This is possibly an error in your program.
            An EXE file, unlike a COM file, must internally setup
            its own stack if it has no stack segment.  To create a
            COM file, use the /c option of WarpLink.


Total number of warnings: 1

EXE load image size: 001K
About to Execute : x2b2 test2.exe test2.bin
X2B2 ecm release 1  -  Public Domain Software by Henry T. Nettles
Input File ==> "test2.exe"  Output File ==> "test2.bin"
Code Size = 32          Code Start = 512         Initial IP = 0
Size of output file = 32
20241205$

In the test2.bin example, the mid section was sectaligned to be paragraph aligned itself, introducing unwanted alignment between the content of START and MID. Desired output, as before, would be a 16-byte test2.bin output file.

20241205$ cat test3.asm

        section START align=1
        nop
        nop
        nop

        section MID align=1
        ds
        es
        ss
        cs

        sectalign off
        align 16

group GROUP START MID
20241205$ ./mak3.sh
About to Execute : warplink /mx test3.obj,test3.exe,test3.map;

WarpLink release 0 by ecm (2024 August), Michael Devore (1989-1993).
Public Domain software, all copyrights surrendered.

Warning in TEST3.EXE
  Problem:  No stack segment was found for the EXE file.
  Solution: This is possibly an error in your program.
            An EXE file, unlike a COM file, must internally setup
            its own stack if it has no stack segment.  To create a
            COM file, use the /c option of WarpLink.


Total number of warnings: 1

EXE load image size: 001K
About to Execute : x2b2 test3.exe test3.bin
X2B2 ecm release 1  -  Public Domain Software by Henry T. Nettles
Input File ==> "test3.exe"  Output File ==> "test3.bin"
Code Size = 19          Code Start = 512         Initial IP = 0
Size of output file = 19
20241205$

In the test3.bin example we used sectalign off but this means the align 16 is local to the MID section and doesn't align to the image level paragraph boundary any longer. Same as the two other examples I want test3.bin to be 16 bytes in size.


Solution

  • I adapted WarpLink in a new revision so it will emit alignment before a section named starting with WLEMITALIGN (regardless group or class), even if the section is empty. This is included in the release 4 build of today.

    Here's a test case. As before, I want DATA as an unaligned mid-section, and to add an empty last section but with its alignment written to the executable file. The last section is now named with a WLEMITALIGN prefix to activate the new feature.

    C:\>type testlink.asm
    
    section CODE
            mov ax, 4C00h
            int 21h
            resb 16
    
    section DATA align=1
            db 26h
    
    section WLEMITALIGNED align=16
    
    section STACK stack
            resb 512
    C:\>testlink.bat
    C:\>ldebug /t /p wl /i /mx testlink.obj,testlink.exe,testlink.map;
    -g
    
    WarpLink release 4 by ecm (2025 September), Michael Devore (1989-1993).
    Public Domain software, all copyrights surrendered.
    
    *** Start of pass 1 on object modules
    *** Processing file: TESTLINK.OBJ
    *** End of pass 1 on object modules
    *** Start of pass 1 on library modules
    *** End of pass 1 on library modules
    *** Start of pass 2 on object modules
    *** Processing file: TESTLINK.OBJ
    *** End of pass 2 on object modules
    *** Start of pass 2 on library modules
    *** End of pass 2 on library modules
    *** Begin writing file(s)
    *** End writing file(s)
    
    EXE load image size: 001K
    
    Program terminated normally (0000)
    -q
    C:\>type testlink.map
    
    PROGRAM: TESTLINK.EXE
    DATE:    2025-09-20
    TIME:    00:10
    
    Start  Stop   Length Name                   Class
    00000H 00014H 00015H CODE
    00015H 00015H 00001H DATA
    00020H 00020H 00000H WLEMITALIGNED
    00020H 0021FH 00200H STACK
    
    
    Detailed Segment Map
    Name             Ovl# Address   Length Align Combine Class    Group     Module       File
    CODE                  0000:0000  0015h BYTE  PUBLIC                     TESTLINK.ASM TESTLINK.OBJ
    DATA                  0001:0005  0001h BYTE  PUBLIC                     TESTLINK.ASM TESTLINK.OBJ
    WLEMITALIGNED         0002:0000  0000h PARA  PUBLIC                     TESTLINK.ASM TESTLINK.OBJ
    STACK                 0002:0000  0200h BYTE  STACK                      TESTLINK.ASM TESTLINK.OBJ
    
     Address   Status   Symbol Name
    
    Program entry point at 0000:0000
    Executable header size 00200h
    Executable initialised image size 00020h
    Executable total image size 00220h
    C:\>