5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
33 test = TestSCons.TestSCons()
35 if sys.platform != 'win32':
36 test.skip_test('PharLap is only available on Windows; skipping test.\n')
38 if not test.detect_tool('linkloc'):
39 test.skip_test("Could not find 'linkloc', skipping test.\n")
41 if not test.detect_tool('386asm'):
42 test.skip_test("Could not find '386asm', skipping test.\n")
44 # From the Phar Lap minasm example program...
45 test.write("minasm.asm", r"""
47 ; MINASM.ASM - A minimal assembly language program which runs
48 ; under ToolSuite. You can use this program as a framework
49 ; for large assembly language programs.
54 ; Segmentation and segment ordering.
56 ; First comes the code segment.
58 _TEXT segment use32 byte public 'CODE'
62 ; The data segment contains initialized RAM based data. It will automatically
63 ; be placed in the ROM at link time and unpacked into RAM at run-time
64 ; by the __pl_unpackrom function.
66 ; If you do not need any initialized data in your assembly language program,
67 ; you can leave this segment empty and remove the call to __pl_unpackrom.
70 _DATA segment use32 dword public 'DATA'
73 rammessage db 'This message is in RAM memory',0dh,0ah,0
78 ; The BSS segment contains RAM based variables which
79 ; are initialized to zero at run-time. Putting unitialized
80 ; variables which should start at zero here saves space in
83 ; If you do not need any zero-initialized data in your assembly language
84 ; program, you can leave this segment empty (and optionally remove the
85 ; instructions below which initialize it).
87 ; The segment name must be lower case for compatibility with the linker
89 _bss segment use32 dword public 'BSS'
90 dummy_bss db 32 dup(?) ; Use a little bit of BSS just to test it
94 ; The const segment contains constants which will never
95 ; change. It is put in the ROM and never copied to RAM.
97 ; If you do not need any ROM based constants in your assembly language
98 ; program, you can leave this segment empty.
100 _CONST segment use32 dword public 'CONST'
101 rommessage db 'This message is in ROM memory',0dh,0ah,0
105 ; We're in flat model, so we'll put all the read-only segments we know about
106 ; in a code group, and the writeable segments in a data group, so that
107 ; we can use assume to easily get addressability to the segments.
109 CGROUP group _TEXT, _CONST
110 DGROUP group _DATA, _bss
112 assume cs:CGROUP,ds:DGROUP
116 ; _main - the main routine of this program.
118 ; We will display the RAM and ROM messages the number of times
119 ; specified in the loopcount variable. This proves that we can
120 ; initialize RAM data out of ROM and the fact that we can
121 ; modify the loop count in memory verifies that it actually ends
127 mov cl,0ah ; Skip a line before we start
130 cmp loopcount,0 ; Are we at the end of our loop?
131 je short done_main ; yes.
132 lea edx,rommessage ; EDX -> ROM message
133 call WriteStringTarget ; Display it
134 lea edx,rammessage ; EDX -> RAM message
135 call WriteStringTarget ; Display it
137 jmp main_loop ; Branch back for next loop iteration
144 ; WriteStringTarget - Display a string on the target console
147 ; EDX -> Null terminated ASCII string to display
150 ; All registers preserved
152 WriteStringTarget proc near
154 push ecx ; Save registers
158 movzx ecx,byte ptr [edx] ; Get a character
159 jecxz done_str ; Branch if end of string
160 call PutCharTarget ; Display this character
161 inc edx ; Bump scan pointer
162 jmp write_loop ; And loop back for next character
165 pop edx ; Restore registers
169 WriteStringTarget endp
172 ; PutCharTarget - Write a character on the target console
174 ; This routine displays a character on the target console by using
175 ; the PutChar kernel service available through int 254.
178 ; CL = character to display
181 ; All registers preserved
183 PutCharTarget proc near
185 push eax ; Save registers
189 mov ax,254Ah ; Request Kernel Service
190 mov bx,1 ; service code 1 = PutChar
191 movzx edx,cl ; EDX = character to display
192 int 0FEh ; Int 254 is for kernel services
194 pop edx ; Restore registers
202 ; The __pl_unpackrom unpacks initialized RAM based data variables
203 ; out of the ROMINIT segment into their RAM area. They are put
204 ; in the ROMINIT segment with the -ROMINIT switch in the link file.
206 extrn __pl_unpackrom:near
209 ; The _EtsExitProcess function is used to terminate our program
211 extrn _EtsExitProcess:near
214 ; The linker will define symbols for the beginning and end of the
217 extrn __p_SEG__bss_BEGIN:dword
218 extrn __p_SEG__bss_END:dword
221 ; __p_start -- The entry point for our assembly language program.
222 ; We unpack the RAM based variables out of the ROM and clear the
223 ; BSS to zero, then call _main where the real work happens. When
224 ; _main returns, we call EtsExitProcess(0) to terminate.
228 pushad ; save initial regs
230 call __pl_unpackrom ; Call the unpacker
231 cld ; Clear direction flag
233 lea eax,__p_SEG__bss_END ; load end address and
234 lea ebx,__p_SEG__bss_BEGIN ; subtract start to get size
236 mov ecx,eax ; This is size
238 lea edi,__p_SEG__bss_BEGIN ; Zero from start address
239 mov al,0 ;Zero out BSS and C_COMMON
242 pop es ; restore initial regs
244 call _main ; go do some work
246 xor eax,eax ; Call _EtsExitProcess(0)
248 call _EtsExitProcess ;
250 jmp stopme ; .. in a loop just in case it ever
256 mov eax, __p_tdhack ; force reference to TD-hack symbol
261 ; Hack for Turbo Debugger/TDEMB - TD will fault if the .exe being
262 ; debugged doesn't have an import table. (TD looks for the address of
263 ; the table, then dereferences that address wihtout checking for NULL).
265 ; This symbol, __p_tdhack, must be declared as an import in all the
266 ; .emb files shipped. IE:
268 ; -implib embkern.lib
271 ; This forces the creation of an import table within the .EXE.
273 extrn __p_tdhack:dword
278 test.write("foo.lnk","""
283 test.write([ "baz", "bar.lnk"],"""
287 test.write("SConstruct", """
288 env=Environment(tools = [ 'linkloc', '386asm' ],
289 ASFLAGS='-twocase -cvsym',
290 LINKFLAGS='@foo.lnk')
291 env.Program(target='minasm', source='minasm.asm')
294 test.run(arguments='.')
296 # Assume .exe extension...this test is for Windows only.
297 test.fail_test(not os.path.exists('minasm.exe'))
298 test.up_to_date(arguments='.')
300 # Updating a linker command file should cause a rebuild!
301 test.write([ "baz", "bar.lnk"],"""
306 oldtime = os.path.getmtime(test.workpath('minasm.exe'))
307 time.sleep(2) # Give the time stamp time to change
308 test.run(arguments = '.')
309 test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe')))
315 # indent-tabs-mode:nil
317 # vim: set expandtab tabstop=4 shiftwidth=4: