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__"
34 test = TestSCons.TestSCons()
36 if sys.platform != 'win32':
37 test.skip_test('PharLap is only available on Windows; skipping test.\n')
39 if not test.detect_tool('linkloc'):
40 test.skip_test("Could not find 'linkloc', skipping test.\n")
42 if not test.detect_tool('386asm'):
43 test.skip_test("Could not find '386asm', skipping test.\n")
45 # From the Phar Lap minasm example program...
46 test.write("minasm.asm", r"""
48 ; MINASM.ASM - A minimal assembly language program which runs
49 ; under ToolSuite. You can use this program as a framework
50 ; for large assembly language programs.
55 ; Segmentation and segment ordering.
57 ; First comes the code segment.
59 _TEXT segment use32 byte public 'CODE'
63 ; The data segment contains initialized RAM based data. It will automatically
64 ; be placed in the ROM at link time and unpacked into RAM at run-time
65 ; by the __pl_unpackrom function.
67 ; If you do not need any initialized data in your assembly language program,
68 ; you can leave this segment empty and remove the call to __pl_unpackrom.
71 _DATA segment use32 dword public 'DATA'
74 rammessage db 'This message is in RAM memory',0dh,0ah,0
79 ; The BSS segment contains RAM based variables which
80 ; are initialized to zero at run-time. Putting unitialized
81 ; variables which should start at zero here saves space in
84 ; If you do not need any zero-initialized data in your assembly language
85 ; program, you can leave this segment empty (and optionally remove the
86 ; instructions below which initialize it).
88 ; The segment name must be lower case for compatibility with the linker
90 _bss segment use32 dword public 'BSS'
91 dummy_bss db 32 dup(?) ; Use a little bit of BSS just to test it
95 ; The const segment contains constants which will never
96 ; change. It is put in the ROM and never copied to RAM.
98 ; If you do not need any ROM based constants in your assembly language
99 ; program, you can leave this segment empty.
101 _CONST segment use32 dword public 'CONST'
102 rommessage db 'This message is in ROM memory',0dh,0ah,0
106 ; We're in flat model, so we'll put all the read-only segments we know about
107 ; in a code group, and the writeable segments in a data group, so that
108 ; we can use assume to easily get addressability to the segments.
110 CGROUP group _TEXT, _CONST
111 DGROUP group _DATA, _bss
113 assume cs:CGROUP,ds:DGROUP
117 ; _main - the main routine of this program.
119 ; We will display the RAM and ROM messages the number of times
120 ; specified in the loopcount variable. This proves that we can
121 ; initialize RAM data out of ROM and the fact that we can
122 ; modify the loop count in memory verifies that it actually ends
128 mov cl,0ah ; Skip a line before we start
131 cmp loopcount,0 ; Are we at the end of our loop?
132 je short done_main ; yes.
133 lea edx,rommessage ; EDX -> ROM message
134 call WriteStringTarget ; Display it
135 lea edx,rammessage ; EDX -> RAM message
136 call WriteStringTarget ; Display it
138 jmp main_loop ; Branch back for next loop iteration
145 ; WriteStringTarget - Display a string on the target console
148 ; EDX -> Null terminated ASCII string to display
151 ; All registers preserved
153 WriteStringTarget proc near
155 push ecx ; Save registers
159 movzx ecx,byte ptr [edx] ; Get a character
160 jecxz done_str ; Branch if end of string
161 call PutCharTarget ; Display this character
162 inc edx ; Bump scan pointer
163 jmp write_loop ; And loop back for next character
166 pop edx ; Restore registers
170 WriteStringTarget endp
173 ; PutCharTarget - Write a character on the target console
175 ; This routine displays a character on the target console by using
176 ; the PutChar kernel service available through int 254.
179 ; CL = character to display
182 ; All registers preserved
184 PutCharTarget proc near
186 push eax ; Save registers
190 mov ax,254Ah ; Request Kernel Service
191 mov bx,1 ; service code 1 = PutChar
192 movzx edx,cl ; EDX = character to display
193 int 0FEh ; Int 254 is for kernel services
195 pop edx ; Restore registers
203 ; The __pl_unpackrom unpacks initialized RAM based data variables
204 ; out of the ROMINIT segment into their RAM area. They are put
205 ; in the ROMINIT segment with the -ROMINIT switch in the link file.
207 extrn __pl_unpackrom:near
210 ; The _EtsExitProcess function is used to terminate our program
212 extrn _EtsExitProcess:near
215 ; The linker will define symbols for the beginning and end of the
218 extrn __p_SEG__bss_BEGIN:dword
219 extrn __p_SEG__bss_END:dword
222 ; __p_start -- The entry point for our assembly language program.
223 ; We unpack the RAM based variables out of the ROM and clear the
224 ; BSS to zero, then call _main where the real work happens. When
225 ; _main returns, we call EtsExitProcess(0) to terminate.
229 pushad ; save initial regs
231 call __pl_unpackrom ; Call the unpacker
232 cld ; Clear direction flag
234 lea eax,__p_SEG__bss_END ; load end address and
235 lea ebx,__p_SEG__bss_BEGIN ; subtract start to get size
237 mov ecx,eax ; This is size
239 lea edi,__p_SEG__bss_BEGIN ; Zero from start address
240 mov al,0 ;Zero out BSS and C_COMMON
243 pop es ; restore initial regs
245 call _main ; go do some work
247 xor eax,eax ; Call _EtsExitProcess(0)
249 call _EtsExitProcess ;
251 jmp stopme ; .. in a loop just in case it ever
257 mov eax, __p_tdhack ; force reference to TD-hack symbol
262 ; Hack for Turbo Debugger/TDEMB - TD will fault if the .exe being
263 ; debugged doesn't have an import table. (TD looks for the address of
264 ; the table, then dereferences that address wihtout checking for NULL).
266 ; This symbol, __p_tdhack, must be declared as an import in all the
267 ; .emb files shipped. IE:
269 ; -implib embkern.lib
272 ; This forces the creation of an import table within the .EXE.
274 extrn __p_tdhack:dword
279 test.write("foo.lnk","""
284 test.write([ "baz", "bar.lnk"],"""
288 test.write("SConstruct", """
289 env=Environment(tools = [ 'linkloc', '386asm' ],
290 ASFLAGS='-twocase -cvsym',
291 LINKFLAGS='@foo.lnk')
292 env.Program(target='minasm', source='minasm.asm')
295 test.run(arguments='.')
297 # Assume .exe extension...this test is for Windows only.
298 test.fail_test(not os.path.exists('minasm.exe'))
299 test.up_to_date(arguments='.')
301 # Updating a linker command file should cause a rebuild!
302 test.write([ "baz", "bar.lnk"],"""
307 oldtime = os.path.getmtime(test.workpath('minasm.exe'))
308 time.sleep(2) # Give the time stamp time to change
309 test.run(arguments = '.')
310 test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe')))