====== Recent WarpLink tests ====== These tests were written to test several of the wlcalc and wllist features during their development. They're all stored in https://pushbx.org/ecm/test/20260204/ ===== The scriptlets ===== The basic assemble and link scriptlet looks like this (as of the most recent WarpLink revision - some of the switches require a newer revision than others). It assembles the test object file, then links it using the local ''warplink.exe'' (a link to the development repo's executable). Then it runs the linker with the /MX, /WS0, /XL, /XS, /XC, /TO=, /TL=, /I, and /XLD switches: (nasm test$NUM.asm -f obj && ~/proj/ldos/warplink.sh /mx /ws0 /xl /xs /xc /to=wllist.obj /tl=wllist.bin /i /xld test$NUM.obj,test$NUM.exe,test$NUM.map\;) To dump the executable image of the output file, the following scriptlet can be used: tail --bytes +513 test$NUM.exe | podhex To run omfdump on the temporary wllist object file: ~/proj/omfdump/omfdump wllist.obj To hex dump the temporary wllist list file: podhex wllist.bin The ''dox.bat'' script is to be run from a DOS that maps the test directory to a DOS directory. It runs the debugger with its /T, /P, and /C switches to load WarpLink and enable serial I/O. The WarpLink command it runs specifies the /TL=, /TO=, /XL, /XC, and /XS switches, along with the older /MX, /WSN, and /WS0. The first parameter, ''%1'', specifies the test number to link. ldebug /t /p /c=install,serial warplink /tl=wllist.bin /to=wllist.obj /xl /xc /xs /mx /wsn /ws0 test%1.obj,test%1.exe,test%1.map; ===== The tests ===== ==== test.asm ==== This creates a code segment with a zeroed word. section code dw 0 ==== test1.asm ==== This uses two wlcalc post-link calculations, to imitate the usual "find number of paragraphs neeeded" for a program where this is less than 64 KiB. section code wlcalc_word_add_15: wlcalc_word_div_16: global wlcalc_word_add_15 global wlcalc_word_div_16 dw label times 26 nop label: ==== test2.asm ==== Like the prior test, but without a label and the order of the global directives is switched. NASM still emits the "add" operation in the PUBDEF record before the "div". section code wlcalc_word_add_15: wlcalc_word_div_16: global wlcalc_word_div_16 global wlcalc_word_add_15 dw 0 ==== test3.asm ==== Like the prior test but the order of the operations is changed again. section code wlcalc_word_div_16: wlcalc_word_add_15: global wlcalc_word_div_16 global wlcalc_word_add_15 dw 0 ==== test4.asm ==== Again a different order of the global directives. NASM still follows the order of the labels, ignoring the differing order of the global directives. section code wlcalc_word_div_16: wlcalc_word_add_15: global wlcalc_word_add_15 global wlcalc_word_div_16 dw 0 ==== test5.asm ==== Place a label as an equate with a dollar sign calculation. NASM emits them in the order the labels are defined in the source (add first, then div) despite the label defined later pointing at an address that's earlier. section code times 4 dw 1234h wlcalc_word_add_15: wlcalc_word_div_16: equ $ - 2 global wlcalc_word_add_15 global wlcalc_word_div_16 dw 100h ==== test6.asm ==== A ''jmp far'' with a destination label in the same segment. section DOSSECTION label: times 4 dw 0 wlcalc_word_add_15: wlcalc_word_div_16: equ $ - 2 global wlcalc_word_add_15 global wlcalc_word_div_16 dw 0 jmp far label ==== test7.asm ==== An ''extern'' label written to a word in the section. section DOSSECTION extern label dw label ==== test8.asm ==== Attempt to cause a common variable overflow. section DOSSECTION common variable 4999999999:1024 ==== test9.asm ==== A wlcalc label as an equate, pointing to the same word as a non-equate wlcalc label. section code times 4 dw 1234h wlcalc_word_add_15: dw 2642h wlcalc_word_div_16: equ $ - 2 global wlcalc_word_add_15 global wlcalc_word_div_16 dw 100h ==== test10.asm ==== Multiple wlcalc requests with differing sizes and trailing identifiers. section code wlcalc_word_shr_4?bar: global wlcalc_word_shr_4?bar: dw 123h nop wlcalc_byte_shr_4?foo: global wlcalc_byte_shr_4?foo: dw 123h nop wlcalc_3byte_shr_4?foo: global wlcalc_3byte_shr_4?foo: dd 0FF123456h wlcalc_dword_shr_4?foo: global wlcalc_dword_shr_4?foo: dd 12345678h int3 ==== test11.asm ==== A wlcalc request with the divisor as zero. section code global wlcalc_word_div_0 wlcalc_word_div_0: dw 1 ==== test12.asm ==== A wlcalc request with a "subr" operation, to negate a label. section code wlcalc_word_subr_0: global wlcalc_word_subr_0: dd label times 16 nop label: ==== test13.asm ==== A wlcalc request that will encounter a short read at the executable's EOF. section code wlcalc_word_subr_0: global wlcalc_word_subr_0: ==== test14.asm ==== A wlemitalign test case. section code times 4 db 0 section WLEMITALIGNdata align=16 ==== test15.asm ==== Multiple new wlcalc requests: OR, MUL, XOR, and AND. section code wlcalc_word_or_4?bar: global wlcalc_word_or_4?bar dw 1000h nop wlcalc_word_mul_256?foo: global wlcalc_word_mul_256?foo dw 26h nop wlcalc_word_xor_4096?bar: global wlcalc_word_xor_4096?bar dw 1000h nop wlcalc_word_and_4096?bar: global wlcalc_word_and_4096?bar dw 1010h nop ==== test16.asm ==== A dword MUL wlcalc request that overflows the variable. section code wlcalc_dword_mul_256?foo: global wlcalc_dword_mul_256?foo dd 11223344h nop ==== test17.asm ==== A CLR wlcalc request. section code wlcalc_dword_clr_256?foo: global wlcalc_dword_clr_256?foo dd -1 nop ==== test18.asm ==== A wlcalc request with a literal >= 64 KiB, and as a hexadecimal number. section code wlcalc_dword_clr_0x10000?foo: global wlcalc_dword_clr_0x10000?foo dd -1 nop ==== test19.asm ==== Multiple wlcalc requests: Hexadecimal, decimal, binary, all with underscore separators within the numbers. section code wlcalc_dword_clr_0xFF_FF?foo: global wlcalc_dword_clr_0xFF_FF?foo dd -1 nop wlcalc_dword_clr_65_535?foo: global wlcalc_dword_clr_65_535?foo dd -1 nop wlcalc_dword_clr_1111_0000B?foo: global wlcalc_dword_clr_1111_0000B?foo dd -1 nop ==== test20.asm ==== A wlcalc request with a constant that overflows the 4 Gi - 1 numeric range. section code wlcalc_dword_clr_1_0000_0000h?foo: global wlcalc_dword_clr_1_0000_0000h?foo dd -1 nop ==== test21.asm ==== The wlcalc helper mmacro for NASM. Several tests of 32-bit constants. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code wlcalc dword_mul_01020304h dd 8 wlcalc 3byte_xor_11223344h dd 0F0F0F0Fh wlcalc dword_div_1230000h dd 1230_0000h ==== test22.asm ==== Repetition of a wlcalc request, and using the wlcalc mmacro with an equate. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc dword_mul_01020304h dd 8 wlcalc 3byte_xor_11223344h dd 0F0F0F0Fh wlcalc dword_div_1230000h dd 1230_0000h %assign AMOUNT ($-$$) / 4 wlcalc dword_xor_FF00FF00h_repeat_%[AMOUNT], equ start ==== test23.asm ==== Like prior example but with additional wlcalc requests in pass 1 and pass 2, to test that the passes are honoured. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc dword_mul_01020304h dd 8 wlcalc 3byte_xor_11223344h wlcalc dword_and_0_pass_1 wlcalc word_or_2642h_repeat_2_pass_2 dd 0F0F0F0Fh wlcalc dword_div_1230000h dd 1230_0000h %assign AMOUNT ($-$$) / 4 wlcalc dword_xor_FF00FF00h_repeat_%[AMOUNT], equ start ==== test24.asm ==== The wlcalc "seg" operation. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc word_seg_data?foo dw 26h wlcalc word_seg_data?bar dw 0 wlcalc word_seg_stack?foo dw 0 dw 0 times 16 nop section data align 16 times 16 nop section stack stack alignb 16 resb 512 ==== test25.asm ==== A wlcalc "seg" operation with an unknown segment name. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc word_seg_data?foo dw 26h wlcalc word_seg_unknown?foo dw 0 times 16 nop section data align 16 ==== test26.asm ==== Another "seg" operation. Unclear why this. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc word_seg_data?foo dw 26h dw 0 times 16 nop section data align 16 ==== test27.asm ==== A wlcalc "seg" operation with a dword variable. This is rejected by the linker. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc word_seg_data?foo dw 26h wlcalc word_seg_data dw 26h wlcalc dword_seg_data?foo dw 0 times 16 nop section data align 16 ==== test28.asm ==== A wlcalc "seg" request at offset 0FFFFh, which is rejected as an overflow. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc word_seg_data?foo dw 26h wlcalc word_seg_data?bar dw 0 wlcalc word_seg_stack?foo dw 0 dw 0 times 16 nop times (0xffff) - ($-$$) db 0 wlcalc word_seg_data?quux section data align 16 times 16 nop section stack stack alignb 16 resb 512 ==== test29.asm ==== A wlcalc sequence involving first shifting right, then in another pass applying a segment relocation ("seg"). %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc word_shr_4 wlcalc word_pass_1_seg_stack dw stack_top + 15 wlcalc word_seg_data?foo dw 26h wlcalc word_seg_data?bar dw 0 wlcalc word_seg_stack?foo dw 0 dw 0 times 16 nop section data align 16 times 16 nop section stack stack alignb 16 resb 512 stack_top: ==== test30.asm ==== Testing the "segrel" and "minussegrel" wlcalc operations. %imacro wlcalc 1-2.nolist global wlcalc_%1 wlcalc_%1: %2 %endmacro section code start: wlcalc word_shr_4 wlcalc word_pass_1_segrel_stack dw stack_top + 15 wlcalc word_segrel_data?foo dw 26h wlcalc word_segrel_data?bar dw 0 wlcalc word_segrel_stack?foo dw 0 wlcalc word_minussegrel_data?bar dw 100h wlcalc word_minussegrel_stack?foo dw 100h dw 0 times 16 nop section data align 16 times 16 nop section stack stack alignb 16 resb 512 stack_top: ==== test31.asm ==== Reference to a label in another section, and making the label global. section code dw 1234h + label section data times 260h nop global label label: ==== test32.asm ==== The first wllist mmacro, and naive draft of two wllist list items. These are invalid to the eventual wllist implementation because the lists aren't declared and the items are missing the "L" key letter to indicate the list name. %imacro wllist 1.nolist global ..@wllist_%1?%[%%l] ..@wllist_%1?%[%%l]: %endmacro section code nop nop global wllist_init_code_386 wllist_init_code_386: dd "Quux" wllist init_code_386 db 26h section init align=1 ==== test33.asm ==== Multiple wllist list declarations, in the "init" and "exit" segments. A wllist declaration of a group, "initgroup", that contains the "init" segment. %imacro wllist 1.nolist global ..@wllist_%1?%[%%l] ..@wllist_%1?%[%%l]: %endmacro section code wllist n_sinit_linit_code_386 wllist n_sexit_lexit_code_386 wllist n_sexit_lexit_code_no386 wllist n_sinit_linit_code_no386 wllist g_ginitgroup_sinit nop nop global wllist_linit_code_386 wllist_linit_code_386: dd "Quux" wllist linit_code_386 db 26h group initgroup init section init align=1 ==== test34.asm ==== Similar to prior, but put the group declaration before the new list declarations. (This still works because of how the declarations are handled.) %imacro wllist 1.nolist global ..@wllist_%1?%[%%l] ..@wllist_%1?%[%%l]: %endmacro section code wllist g_ginitgroup_sinit wllist n_sinit_linit_code_386 wllist n_sexit_lexit_code_386 wllist n_sexit_lexit_code_no386 wllist n_sinit_linit_code_no386 nop nop global wllist_linit_code_386 wllist_linit_code_386: dd "Quux" wllist linit_code_386 db 26h group initgroup init section init align=1 ==== test35.asm ==== A wllist group declaration that includes an unknown section name, "omit". %imacro wllist 1.nolist global ..@wllist_%1?%[%%l] ..@wllist_%1?%[%%l]: %endmacro section code wllist g_ginitgroup_somit wllist n_sinit_linit_code_386 wllist n_sexit_lexit_code_386 wllist n_sexit_lexit_code_no386 wllist n_sinit_linit_code_no386 nop nop global wllist_linit_code_386 wllist_linit_code_386: dd "Quux" wllist linit_code_386 db 26h group initgroup init section init align=1 ==== test36.asm ==== Multiple group declarations, one of them containing multiple segments. %imacro wllist 1.nolist global ..@wllist_%1?%[%%l] ..@wllist_%1?%[%%l]: %endmacro section code wllist g_gexitgroup_sexit wllist g_ginitgroup_sinit_stest wllist n_sinit_linit_code_386 wllist n_sexit_lexit_code_386 wllist n_sexit_lexit_code_no386 wllist n_sinit_linit_code_no386 wllist n_stest_ltest nop nop global wllist_linit_code_386 wllist_linit_code_386: dd "Quux" wllist linit_code_386 db 26h group initgroup init section init align=1 ==== test37.asm ==== Entering a large number of entries into the "init_code_no386" list. %imacro wllist 1.nolist global ..@wllist_%1?%[%%l] ..@wllist_%1?%[%%l]: %endmacro section code wllist g_gexitgroup_sexit wllist g_ginitgroup_sinit_stest wllist n_sinit_linit_code_386 wllist n_sexit_lexit_code_386 wllist n_sexit_lexit_code_no386 wllist n_sinit_linit_code_no386 wllist n_stest_ltest nop nop global wllist_linit_code_386 wllist_linit_code_386: dd "Quux" wllist linit_code_386 db 26h %rep 100 wllist linit_code_no386 nop %endrep group initgroup init section init align=1 ==== test38.asm ==== This test creates a small test program that patches part of its code. It uses the symbols generated as PUBDEF records in the wllist object file, and also checks that the list amount and list end symbols match one another. The wllist mmacro accepts a second parameter to use it as an equate. %imacro wllist 1-2.nolist global ..@wllist_%1?%[%%l] ..@wllist_%1?%[%%l]: %2 %endmacro section code wllist g_ginitgroup_sinit wllist n_sinit_linit_code_386 wllist n_sinit_linit_code_no386 mov ax, init mov ds, ax extern init_code_386 extern init_code_386.end extern init_code_386.amount extern init_code_no386 extern init_code_no386.end extern init_code_no386.amount mov si, init_code_386 mov cx, init_code_386.amount l: lodsw loop l cmp si, init_code_386.end jne error mov si, init_code_no386 mov cx, init_code_no386.amount q: lodsw xchg di, ax mov byte [cs:di], 90h loop q cmp si, init_code_no386.end jne error align 64 nop nop wllist linit_code_386 mov ax, 1234h nop wllist linit_code_386 inc ax wllist linit_code_no386 o32 push ax wllist linit_code_no386 o32 push bx wllist linit_code_no386 o32 push cx wllist linit_code_no386 o32 push dx mov al, '^' wllist linit_code_no386, equ $ - 1 mov ax, 4C00h int 21h error: mov ax, 4CFFh int 21h group initgroup init section init align=1 ==== test39.asm ==== Based on prior. Additionally, test the wllist repetition and repetition step width features. Also test that zero repetition and different bases for the repetition count work. %imacro wllist 1-2.nolist global ..@wllist_%1?%[%%l] ..@wllist_%1?%[%%l]: %2 %endmacro section code wllist g_ginitgroup_sinit wllist n_sinit_linit_code_386 wllist n_sinit_linit_code_no386 wllist n_sinit_lemptylist mov ax, init mov ds, ax extern init_code_386 extern init_code_386.end extern init_code_386.amount extern init_code_no386 extern init_code_no386.end extern init_code_no386.amount mov si, init_code_386 mov cx, init_code_386.amount l: lodsw loop l cmp si, init_code_386.end jne error mov si, init_code_no386 mov cx, init_code_no386.amount q: lodsw xchg di, ax mov byte [cs:di], 90h loop q cmp si, init_code_no386.end jne error align 64 nop nop wllist linit_code_386 mov ax, 1234h nop wllist linit_code_386 inc ax wllist linit_code_no386 o32 push ax wllist linit_code_no386 o32 push bx wllist linit_code_no386 o32 push cx wllist linit_code_no386 o32 push dx wllist r4_w2_linit_code_no386 pop edx pop ecx pop ebx pop eax xor bx, bx wllist r3_linit_code_no386 mov bx, 2642h wllist r0_linit_code_no386 wllist r0x0_linit_code_no386 wllist r0h_linit_code_no386 wllist r0_0_0b_linit_code_no386 mov al, '^' wllist linit_code_no386, equ $ - 1 wllist r0_w26h_lemptylist mov ax, 4C00h int 21h error: mov ax, 4CFFh int 21h group initgroup init section init align=1 {{tag>warplink testspam}} ~~DISCUSSION~~