initial commit: a mess of assembly code
[fmap.git] / x86_64_sse2_x87 / fasm / source / output.inc
blobd96c3561b32d356bc13945427e281b269dd8bc02
1 \r
2 struct OutputArea\r
3         cached_offset dq ?\r
4         definition dd ?                 ; pointer to ValueDefinition\r
5 ends\r
6 \r
7 struct AreaHeader\r
8         flags dd ?                      ; AREA_#\r
9         base_address_length dd ?\r
10         uninitialized_length dd ?\r
11 ends\r
13 AREA_VIRTUAL = 1\r
14 AREA_VARIABLE = 2\r
15 AREA_SHIFT_TRACKING_DISABLED = 4\r
17 create_output_area:\r
18 ; in:\r
19 ;  esi - base address in format of VALTYPE_NUMERIC value\r
20 ;  ecx = length of base address value\r
21 ; out:\r
22 ;  ebx - AreaHeader\r
23 ;  edx - ValueDefinition\r
24         mov     eax,[current_output_area_entry]\r
25         test    eax,eax\r
26         jz      create_first_output_area\r
27         push    ecx\r
28         lea     ecx,[eax+sizeof.OutputArea*2]\r
29         cmp     ecx,[output_areas_list_end]\r
30         jbe     get_next_output_entry\r
31         mov     eax,[output_areas_list]\r
32         sub     ecx,eax\r
33         sub     [current_output_area_entry],eax\r
34         sub     [initial_output_area_entry],eax\r
35         sub     [output_areas_list_end],eax\r
36         call    grow_stack\r
37         mov     [output_areas_list],eax\r
38         add     [current_output_area_entry],eax\r
39         add     [initial_output_area_entry],eax\r
40         add     eax,ecx\r
41         mov     edi,eax\r
42         xchg    [output_areas_list_end],eax\r
43         sub     ecx,eax\r
44         sub     edi,ecx\r
45         shr     ecx,2\r
46         xor     eax,eax\r
47         rep     stosd\r
48         mov     eax,[current_output_area_entry]\r
49     get_next_output_entry:\r
50         add     eax,sizeof.OutputArea\r
51         cmp     [initial_output_area_entry],0\r
52         je      another_initial_output_area\r
53         mov     edi,[eax-sizeof.OutputArea+OutputArea.definition]\r
54         mov     ecx,[edi+ValueDefinition.value_length]\r
55         mov     edi,[edi+ValueDefinition.value]\r
56         mov     ebx,[edi+AreaHeader.uninitialized_length]\r
57         sub     ecx,sizeof.AreaHeader\r
58         sub     ecx,[edi+AreaHeader.base_address_length]\r
59         jz      prior_uninitialized_length_ok\r
60         and     dword [prior_uninitialized_length],0\r
61         and     dword [prior_uninitialized_length+4],0\r
62     prior_uninitialized_length_ok:\r
63         add     dword [prior_uninitialized_length],ebx\r
64         adc     dword [prior_uninitialized_length+4],0\r
65         xor     edx,edx\r
66         add     ecx,ebx\r
67         adc     edx,0\r
68         add     ecx,dword [eax-sizeof.OutputArea+OutputArea.cached_offset]\r
69         adc     edx,dword [eax-sizeof.OutputArea+OutputArea.cached_offset+4]\r
70         mov     dword [eax+OutputArea.cached_offset],ecx\r
71         mov     dword [eax+OutputArea.cached_offset+4],edx\r
72         pop     ecx\r
73         jmp     new_output_entry_ready\r
74     another_initial_output_area:\r
75         pop     ecx\r
76         jmp     create_initial_output_area\r
77     create_first_output_area:\r
78         mov     eax,[output_areas_list]\r
79     create_initial_output_area:\r
80         mov     [initial_output_area_entry],eax\r
81         and     dword [eax+OutputArea.cached_offset],0\r
82         and     dword [eax+OutputArea.cached_offset+4],0\r
83         and     dword [prior_uninitialized_length],0\r
84         and     dword [prior_uninitialized_length+4],0\r
85     new_output_entry_ready:\r
86         mov     [current_output_area_entry],eax\r
87         lea     ebx,[eax+OutputArea.definition]\r
88         call    create_area\r
89         retn\r
91 create_area:\r
92 ; in:\r
93 ;  ebx - where pointer to ValueDefinition should be stored, may already hold a previously used one (should contain null otherwise)\r
94 ;  esi - base address in format of VALTYPE_NUMERIC value\r
95 ;  ecx = length of base address value\r
96 ; out:\r
97 ;  ebx - AreaHeader\r
98 ;  edx - ValueDefinition\r
99         mov     [address_length],ecx\r
100         mov     edx,[ebx]\r
101         test    edx,edx\r
102         jz      current_area_definition_unusable\r
103         cmp     [edx+ValueDefinition.reference_count],1\r
104         je      area_definition_ready\r
105         dec     [edx+ValueDefinition.reference_count]\r
106     current_area_definition_unusable:\r
107         mov     ecx,retired_definition\r
108       retrieve_retired_detached_value:\r
109         mov     edx,[ecx]\r
110         test    edx,edx\r
111         jz      create_area_definition\r
112         cmp     [edx+ValueDefinition.reference_count],0\r
113         jne     retired_detached_value_immutable\r
114         xor     eax,eax\r
115         xchg    eax,[edx+ValueDefinition.previous]\r
116         mov     [ecx],eax\r
117         jmp     adopt_area_definition\r
118       retired_detached_value_immutable:\r
119         lea     ecx,[edx+ValueDefinition.previous]\r
120         jmp     retrieve_retired_detached_value\r
121     create_area_definition:\r
122         mov     ecx,sizeof.ValueDefinition\r
123         call    create_tree_element\r
124         mov     ecx,eax\r
125         xchg    ecx,[value_definition_chain]\r
126         mov     [eax+ValueDefinition.interlink],ecx\r
127         mov     edx,eax\r
128     adopt_area_definition:\r
129         mov     [ebx],edx\r
130         or      [edx+ValueDefinition.flags],VAL_DETACHED\r
131         inc     [edx+ValueDefinition.reference_count]\r
132     area_definition_ready:\r
133         mov     ecx,[address_length]\r
134         add     ecx,sizeof.AreaHeader\r
135         mov     eax,[edx+ValueDefinition.block_length]\r
136         test    eax,eax\r
137         jz      allocate_area_block\r
138         cmp     ecx,eax\r
139         jbe     initialize_area_block\r
140         push    ecx edx\r
141         xor     eax,eax\r
142         xchg    eax,[edx+ValueDefinition.value]\r
143         call    mfree\r
144         pop     edx ecx\r
145     allocate_area_block:\r
146         push    edx\r
147         call    malloc_growable\r
148         pop     edx\r
149         mov     [edx+ValueDefinition.value],eax\r
150         mov     [edx+ValueDefinition.block_length],ecx\r
151     initialize_area_block:\r
152         mov     ebx,[edx+ValueDefinition.value]\r
153         lea     edi,[ebx+sizeof.AreaHeader]\r
154         mov     ecx,[address_length]\r
155         mov     [ebx+AreaHeader.base_address_length],ecx\r
156         rep     movsb\r
157         mov     [ebx+AreaHeader.uninitialized_length],ecx\r
158         mov     [ebx+AreaHeader.flags],ecx\r
159         sub     edi,ebx\r
160         mov     [edx+ValueDefinition.value_length],edi\r
161         mov     [edx+ValueDefinition.type],VALTYPE_AREA\r
162         mov     ecx,[current_pass]\r
163         mov     [edx+ValueDefinition.pass],ecx\r
164         retn\r
166 initialize_output:\r
167 ; in: ecx = number of bytes that should be added to output\r
168 ; out: edi - output buffer to be filled with data\r
169 ; preserves: esi\r
170         mov     edx,[current_area]\r
171         mov     ebx,[edx+ValueDefinition.value]\r
172         add     ecx,[ebx+AreaHeader.uninitialized_length]\r
173         jc      output_out_of_memory\r
174         mov     eax,[edx+ValueDefinition.value_length]\r
175         lea     edi,[ebx+eax]\r
176         add     ecx,eax\r
177         jc      output_out_of_memory\r
178         mov     [edx+ValueDefinition.value_length],ecx\r
179         cmp     ecx,[edx+ValueDefinition.block_length]\r
180         jbe     area_reserve_sufficient\r
181         mov     eax,[edx+ValueDefinition.value]\r
182         sub     edi,eax\r
183         push    edx\r
184         push    ecx\r
185         bsr     edx,ecx\r
186         xchg    ecx,edx\r
187         dec     cl\r
188         shr     edx,cl\r
189         inc     edx\r
190         shl     edx,cl\r
191         pop     ecx\r
192         cmp     edx,ecx\r
193         jbe     output_out_of_memory\r
194         xchg    ecx,edx\r
195         call    realloc\r
196         pop     edx\r
197         mov     ebx,eax\r
198         add     edi,eax\r
199         mov     [edx+ValueDefinition.value],ebx\r
200         mov     [edx+ValueDefinition.block_length],ecx\r
201     area_reserve_sufficient:\r
202         mov     ecx,[ebx+AreaHeader.uninitialized_length]\r
203         jecxz   output_buffer_ready\r
204         xor     eax,eax\r
205         mov     dl,cl\r
206         shr     ecx,2\r
207         rep     stosd\r
208         mov     cl,dl\r
209         and     cl,11b\r
210         rep     stosb\r
211         mov     [ebx+AreaHeader.uninitialized_length],eax\r
212     output_buffer_ready:\r
213         retn\r
214     output_out_of_memory:\r
215         jmp     out_of_memory\r
217 uninitialized_output:\r
218 ; in: ecx = number of uninitialized bytes to be added to output\r
219 ; preserves: ebx, ecx, esi, edi\r
220         mov     edx,[current_area]\r
221         mov     eax,[edx+ValueDefinition.value]\r
222         add     [eax+AreaHeader.uninitialized_length],ecx\r
223         jc      area_overflow\r
224         mov     edx,[edx+ValueDefinition.value_length]\r
225         sub     edx,sizeof.AreaHeader\r
226         sub     edx,[eax+AreaHeader.base_address_length]\r
227         add     edx,[eax+AreaHeader.uninitialized_length]\r
228         jc      area_overflow\r
229         retn\r
230     area_overflow:\r
231         mov     edx,_area_overflow\r
232         call    register_error\r
233         mov     edx,[current_area]\r
234         or      ecx,-1\r
235         mov     eax,[edx+ValueDefinition.value]\r
236         sub     ecx,[edx+ValueDefinition.value_length]\r
237         add     ecx,sizeof.AreaHeader\r
238         add     ecx,[eax+AreaHeader.base_address_length]\r
239         mov     [eax+AreaHeader.uninitialized_length],ecx\r
240         retn\r
242 trim_output:\r
243 ; preserves: ecx, esi\r
244         xor     eax,eax\r
245         mov     dword [prior_uninitialized_length],eax\r
246         mov     dword [prior_uninitialized_length+4],eax\r
247         mov     edi,[current_output_area_entry]\r
248     trim_current_output_area:\r
249         mov     edx,[edi+OutputArea.definition]\r
250         mov     eax,[edx+ValueDefinition.value]\r
251         and     [eax+AreaHeader.uninitialized_length],0\r
252         mov     ebx,[edx+ValueDefinition.value_length]\r
253         sub     ebx,sizeof.AreaHeader\r
254         sub     ebx,[eax+AreaHeader.base_address_length]\r
255         jnz     output_trimmed\r
256         cmp     edi,[initial_output_area_entry]\r
257         je      output_trimmed\r
258         sub     edi,sizeof.OutputArea\r
259         jmp     trim_current_output_area\r
260     output_trimmed:\r
261         mov     [current_output_area_entry],edi\r
262         retn\r
264 find_output_area:\r
265 ; in:\r
266 ;  [file_offset] = offset within the output\r
267 ; out:\r
268 ;  cf set when not found an area that would contain a byte at specified offset\r
269 ;  when cf = 0:\r
270 ;   ebx - OutputArea\r
271 ;   [file_offset] = offset relative to the beginning of the found area (upper 32 bits are zero)\r
272         mov     esi,[initial_output_area_entry]\r
273         mov     edi,[current_output_area_entry]\r
274         add     edi,sizeof.OutputArea\r
275     search_areas:\r
276         mov     ebx,edi\r
277         sub     ebx,esi\r
278         jz      output_area_not_found\r
279         test    ebx,1 shl bsf sizeof.OutputArea\r
280         jz      bisect_areas_list\r
281         sub     ebx,sizeof.OutputArea\r
282     bisect_areas_list:\r
283         shr     ebx,1\r
284         add     ebx,esi\r
285         mov     eax,dword [file_offset]\r
286         mov     edx,dword [file_offset+4]\r
287         sub     eax,dword [ebx+OutputArea.cached_offset]\r
288         sbb     edx,dword [ebx+OutputArea.cached_offset+4]\r
289         jc      search_earlier_areas\r
290         jnz     search_later_areas\r
291         mov     edx,[ebx+OutputArea.definition]\r
292         mov     ecx,[edx+ValueDefinition.value_length]\r
293         mov     edx,[edx+ValueDefinition.value]\r
294         sub     ecx,sizeof.AreaHeader\r
295         sub     ecx,[edx+AreaHeader.base_address_length]\r
296         add     ecx,[edx+AreaHeader.uninitialized_length]\r
297         cmp     eax,ecx\r
298         jae     search_later_areas\r
299     output_area_found:\r
300         mov     dword [file_offset],eax\r
301         and     dword [file_offset+4],0\r
302        ; clc\r
303         retn\r
304     output_area_not_found:\r
305         stc\r
306         retn\r
307     search_later_areas:\r
308         lea     esi,[ebx+sizeof.OutputArea]\r
309         jmp     search_areas\r
310     search_earlier_areas:\r
311         mov     edi,ebx\r
312         jmp     search_areas\r
314 read_from_output:\r
315 ; in:\r
316 ;  edi - buffer for read data\r
317 ;  [value_length] = length of data to read\r
318 ;  [file_offset] = offset within the output\r
319 ; out:\r
320 ;  [value_length] = number of bytes that were not in the existing output and could not be read\r
321         push    edi\r
322         call    find_output_area\r
323         pop     edi\r
324         jc      output_reading_done\r
325     read_output_areas:\r
326         cmp     [value_length],0\r
327         je      output_reading_done\r
328         mov     edx,[ebx+OutputArea.definition]\r
329         mov     ecx,[edx+ValueDefinition.value_length]\r
330         mov     eax,ecx\r
331         mov     edx,[edx+ValueDefinition.value]\r
332         sub     ecx,sizeof.AreaHeader\r
333         sub     ecx,[edx+AreaHeader.base_address_length]\r
334         sub     dword [file_offset],ecx\r
335         jnc     initialized_load_done\r
336         lea     esi,[edx+eax]\r
337         mov     ecx,dword [file_offset]\r
338         add     esi,ecx\r
339         neg     ecx\r
340         cmp     ecx,[value_length]\r
341         jbe     initialized_load_length_ok\r
342         mov     ecx,[value_length]\r
343       initialized_load_length_ok:\r
344         sub     [value_length],ecx\r
345         rep     movsb\r
346         mov     dword [file_offset],ecx\r
347       initialized_load_done:\r
348         mov     ecx,[edx+AreaHeader.uninitialized_length]\r
349         sub     dword [file_offset],ecx\r
350         jnc     uninitialized_load_done\r
351         mov     ecx,dword [file_offset]\r
352         neg     ecx\r
353         cmp     ecx,[value_length]\r
354         jbe     uninitialized_load_length_ok\r
355         mov     ecx,[value_length]\r
356       uninitialized_load_length_ok:\r
357         sub     [value_length],ecx\r
358         xor     al,al\r
359         rep     stosb\r
360         mov     dword [file_offset],ecx\r
361       uninitialized_load_done:\r
362         cmp     ebx,[current_output_area_entry]\r
363         je      output_reading_done\r
364         add     ebx,sizeof.OutputArea\r
365         jmp     read_output_areas\r
366     output_reading_done:\r
367         retn\r
369 rewrite_output:\r
370 ; in:\r
371 ;  esi - data to write\r
372 ;  [value_length] = length of data to write\r
373 ;  [file_offset] = offset within the output\r
374 ; out:\r
375 ;  [value_length] = number of bytes that were not in the existing output and could not be rewritten\r
376         push    esi\r
377         call    find_output_area\r
378         pop     esi\r
379         jc      output_rewriting_done\r
380     rewrite_output_areas:\r
381         cmp     [value_length],0\r
382         je      output_rewriting_done\r
383         mov     edx,[ebx+OutputArea.definition]\r
384         mov     ecx,[edx+ValueDefinition.value_length]\r
385         mov     edx,[edx+ValueDefinition.value]\r
386         sub     ecx,sizeof.AreaHeader\r
387         sub     ecx,[edx+AreaHeader.base_address_length]\r
388         mov     edi,[edx+AreaHeader.uninitialized_length]\r
389         add     ecx,edi\r
390         sub     dword [file_offset],ecx\r
391         jnc     rewrite_next_area\r
392         mov     eax,[value_length]\r
393         xor     ecx,ecx\r
394         add     eax,edi\r
395         adc     ecx,ecx\r
396         add     eax,dword [file_offset]\r
397         jnc     rewrite_initialized_data\r
398         cmp     eax,edi\r
399         jbe     rewrite_uninitialized_data\r
400         mov     eax,edi\r
401       rewrite_uninitialized_data:\r
402         test    eax,eax\r
403         jz      rewrite_initialized_data\r
404         push    ebx\r
405         sub     [edx+AreaHeader.uninitialized_length],eax\r
406         mov     edx,[ebx+OutputArea.definition]\r
407         mov     ebx,eax\r
408         call    expand_value\r
409         call    update_output_offsets\r
410         pop     ebx\r
411       rewrite_initialized_data:\r
412         mov     edx,[ebx+OutputArea.definition]\r
413         mov     ecx,[edx+ValueDefinition.value_length]\r
414         mov     edi,[edx+ValueDefinition.value]\r
415         or      [edi+AreaHeader.flags],AREA_VARIABLE\r
416         add     edi,[edi+AreaHeader.uninitialized_length]\r
417         add     edi,ecx\r
418         mov     ecx,dword [file_offset]\r
419         add     edi,ecx\r
420         neg     ecx\r
421         cmp     ecx,[value_length]\r
422         jbe     rewrite_length_ok\r
423         mov     ecx,[value_length]\r
424       rewrite_length_ok:\r
425         sub     [value_length],ecx\r
426         rep     movsb\r
427         mov     dword [file_offset],ecx\r
428       rewrite_next_area:\r
429         cmp     ebx,[current_output_area_entry]\r
430         je      output_rewriting_done\r
431         add     ebx,sizeof.OutputArea\r
432         jmp     rewrite_output_areas\r
433     output_rewriting_done:\r
434         retn\r
436 update_output_offsets:\r
437 ; in:\r
438 ;  edx - ValueDefinition of output area that had some of uninitialized data made initialized\r
439 ; preserves: esi\r
440         mov     eax,[current_output_area_entry]\r
441         cmp     edx,[eax+OutputArea.definition]\r
442         je      output_offsets_ok\r
443         and     dword [prior_uninitialized_length],0\r
444         and     dword [prior_uninitialized_length+4],0\r
445     recount_prior_uninitialized_length:\r
446         cmp     eax,[initial_output_area_entry]\r
447         je      output_offsets_ok\r
448         sub     eax,sizeof.OutputArea\r
449         mov     edi,[eax+OutputArea.definition]\r
450         mov     ebx,[edi+ValueDefinition.value]\r
451         mov     ecx,[ebx+AreaHeader.uninitialized_length]\r
452         add     dword [prior_uninitialized_length],ecx\r
453         adc     dword [prior_uninitialized_length+4],0\r
454         cmp     edx,edi\r
455         je      output_offsets_ok\r
456         mov     ecx,[edi+ValueDefinition.value_length]\r
457         sub     ecx,sizeof.AreaHeader\r
458         sub     ecx,[ebx+AreaHeader.base_address_length]\r
459         jz      recount_prior_uninitialized_length\r
460     output_offsets_ok:\r
461         retn\r
463 get_current_address_value:\r
464 ; out:\r
465 ;  esi - address in format of VALTYPE_NUMERIC value\r
466 ;  ecx = length of address value\r
467 ; note: the returned value is placed in assembly workspace\r
468         mov     eax,[current_area]\r
469         mov     esi,[eax+ValueDefinition.value]\r
470         mov     ebx,[eax+ValueDefinition.value_length]\r
471         mov     edx,assembly_workspace\r
472         mov     edi,[edx+Workspace.memory_start]\r
473         mov     ecx,[esi+AreaHeader.base_address_length]\r
474         add     ecx,4\r
475         call    reserve_workspace\r
476         mov     ecx,[esi+AreaHeader.base_address_length]\r
477         sub     ebx,ecx\r
478         sub     ebx,sizeof.AreaHeader\r
479         add     ebx,[esi+AreaHeader.uninitialized_length]\r
480        ; jc      internal_error\r
481         add     esi,sizeof.AreaHeader\r
482         xor     eax,eax\r
483         stosd\r
484         lodsd\r
485         mov     ecx,eax\r
486         xor     edx,edx\r
487         jecxz   offset_added_to_base_address\r
488     add_offset_to_base_address:\r
489         lodsb\r
490         add     al,bl\r
491         setc    dl\r
492         stosb\r
493         shr     ebx,8\r
494         add     ebx,edx\r
495         loop    add_offset_to_base_address\r
496     offset_added_to_base_address:\r
497         mov     edx,[assembly_workspace.memory_start]\r
498         add     edx,4\r
499         mov     eax,ebx\r
500         cmp     byte [esi-1],80h\r
501         cmc\r
502         sbb     eax,0\r
503         stosd\r
504     optimize_base_address:\r
505         movsx   eax,byte [edi-2]\r
506         cmp     ah,[edi-1]\r
507         jne     base_address_ready\r
508         dec     edi\r
509         cmp     edi,edx\r
510         jne     optimize_base_address\r
511     base_address_ready:\r
512         mov     ecx,edi\r
513         sub     ecx,edx\r
514         mov     [edx-4],ecx\r
515         mov     ecx,esi\r
516     measure_variable_terms:\r
517         lodsd\r
518         test    eax,eax\r
519         jz      variable_terms_measured\r
520         lodsd\r
521         add     esi,eax\r
522         jmp     measure_variable_terms\r
523     variable_terms_measured:\r
524         xchg    ecx,esi\r
525         sub     ecx,esi\r
526         mov     al,cl\r
527         shr     ecx,2\r
528         rep     movsd\r
529         mov     cl,al\r
530         and     cl,11b\r
531         rep     movsb\r
532         mov     esi,[assembly_workspace.memory_start]\r
533         mov     ecx,edi\r
534         sub     ecx,esi\r
535         retn\r
537 get_output_length:\r
538 ; out:\r
539 ;  edx:eax = length of current output (not counting uninitialized data)\r
540 ; preserves: esi\r
541         mov     ebx,[current_output_area_entry]\r
542         mov     eax,dword [ebx+OutputArea.cached_offset]\r
543         mov     edx,dword [ebx+OutputArea.cached_offset+4]\r
544         mov     edi,[ebx+OutputArea.definition]\r
545         mov     ecx,[edi+ValueDefinition.value_length]\r
546         mov     edi,[edi+ValueDefinition.value]\r
547         sub     ecx,sizeof.AreaHeader\r
548         sub     ecx,[edi+AreaHeader.base_address_length]\r
549         jz      current_area_entirely_uninitialized\r
550         add     eax,ecx\r
551         adc     edx,0\r
552         retn\r
553     current_area_entirely_uninitialized:\r
554         sub     eax,dword [prior_uninitialized_length]\r
555         sbb     edx,dword [prior_uninitialized_length+4]\r
556         retn\r
558 get_output_position:\r
559 ; out:\r
560 ;  edx:eax = current position in the output (including uninitialized data)\r
561 ; preserves: esi\r
562         mov     ebx,[current_output_area_entry]\r
563         mov     eax,dword [ebx+OutputArea.cached_offset]\r
564         mov     edx,dword [ebx+OutputArea.cached_offset+4]\r
565         mov     edi,[ebx+OutputArea.definition]\r
566         mov     ecx,[edi+ValueDefinition.value_length]\r
567         mov     edi,[edi+ValueDefinition.value]\r
568         sub     ecx,sizeof.AreaHeader\r
569         sub     ecx,[edi+AreaHeader.base_address_length]\r
570         add     ecx,[edi+AreaHeader.uninitialized_length]\r
571         add     eax,ecx\r
572         adc     edx,0\r
573         retn\r
575 create_output_path:\r
576 ; in:\r
577 ;  ebx - base path and name\r
578 ;  esi - file extension\r
579 ;  ecx = length of the extension\r
580 ; out:\r
581 ;  edx - output path (generated in temporary storage)\r
582         push    ecx\r
583         mov     edi,ebx\r
584         xor     al,al\r
585         or      ecx,-1\r
586         repne   scasb\r
587         dec     edi\r
588         mov     ecx,edi\r
589     locate_extension:\r
590         cmp     edi,ebx\r
591         je      copy_path_name\r
592         dec     edi\r
593         mov     al,[edi]\r
594         cmp     al,'\'\r
595         je      copy_path_name\r
596         cmp     al,'/'\r
597         je      copy_path_name\r
598         cmp     al,'.'\r
599         jne     locate_extension\r
600         mov     ecx,edi\r
601     copy_path_name:\r
602         sub     ecx,ebx\r
603         push    ecx\r
604         mov     edi,[preprocessing_workspace.memory_start]\r
605         inc     ecx\r
606         mov     edx,preprocessing_workspace\r
607         call    reserve_workspace\r
608         pop     ecx\r
609         xchg    esi,ebx\r
610         rep     movsb\r
611         mov     esi,ebx\r
612         pop     ecx\r
613         mov     ebx,ecx\r
614         add     ecx,2\r
615         call    reserve_workspace\r
616         mov     ecx,ebx\r
617         jecxz   extension_attached\r
618         mov     al,'.'\r
619         stosb\r
620         rep     movsb\r
621     extension_attached:\r
622         xor     al,al\r
623         stosb\r
624         mov     edx,[preprocessing_workspace.memory_start]\r
625         retn\r
627 write_output_file:\r
628 ; in:\r
629 ;  ebx - source path\r
630 ;  edi - output path\r
631 ; out:\r
632 ;  cf set when write failed\r
633 ; note:\r
634 ;  when output path is null, source path is used with replaced or attached extension\r
635         mov     [base_path],edi\r
636         xor     eax,eax\r
637         mov     [output_failures],eax\r
638         mov     dword [uninitialized_length],eax\r
639         mov     dword [uninitialized_length+4],eax\r
640         mov     edx,edi\r
641         test    edx,edx\r
642         jnz     create_output_file\r
643         mov     [base_path],ebx\r
644         mov     esi,[output_extension]\r
645         mov     ecx,[output_extension_length]\r
646         call    create_output_path\r
647     create_output_file:\r
648         call    create\r
649         jc      output_write_failed\r
650         mov     esi,[initial_output_area_entry]\r
651     write_area:\r
652         mov     edx,[esi+OutputArea.definition]\r
653         mov     eax,[edx+ValueDefinition.value]\r
654         mov     ecx,[edx+ValueDefinition.value_length]\r
655         sub     ecx,[eax+AreaHeader.base_address_length]\r
656         sub     ecx,sizeof.AreaHeader\r
657         jz      write_next_area\r
658         mov     eax,dword [uninitialized_length]\r
659         or      eax,dword [uninitialized_length+4]\r
660         jz      write_initialized_data\r
661     write_uninitialized_data:\r
662         mov     edi,[assembly_workspace.memory_start]\r
663         mov     ecx,1000h shr 2\r
664         xor     eax,eax\r
665         rep     stosd\r
666         mov     ecx,1000h\r
667         cmp     dword [uninitialized_length+4],0\r
668         jne     portion_length_ok\r
669         cmp     ecx,dword [uninitialized_length]\r
670         jbe     portion_length_ok\r
671         mov     ecx,dword [uninitialized_length]\r
672     portion_length_ok:\r
673         sub     dword [uninitialized_length],ecx\r
674         sbb     dword [uninitialized_length+4],0\r
675         mov     edx,[assembly_workspace.memory_start]\r
676         call    write\r
677         jc      file_write_failed\r
678         mov     eax,dword [uninitialized_length]\r
679         or      eax,dword [uninitialized_length+4]\r
680         jnz     write_uninitialized_data\r
681     write_initialized_data:\r
682         mov     edx,[esi+OutputArea.definition]\r
683         mov     eax,[edx+ValueDefinition.value]\r
684         mov     ecx,[edx+ValueDefinition.value_length]\r
685         mov     edx,[eax+AreaHeader.base_address_length]\r
686         add     edx,sizeof.AreaHeader\r
687         sub     ecx,edx\r
688         add     edx,eax\r
689         call    write\r
690         jc      file_write_failed\r
691     write_next_area:\r
692         mov     edx,[esi+OutputArea.definition]\r
693         mov     eax,[edx+ValueDefinition.value]\r
694         mov     eax,[eax+AreaHeader.uninitialized_length]\r
695         add     dword [uninitialized_length],eax\r
696         adc     dword [uninitialized_length+4],0\r
697         cmp     esi,[current_output_area_entry]\r
698         je      close_output_file\r
699         add     esi,sizeof.OutputArea\r
700         jmp     write_area\r
701     close_output_file:\r
702         call    close\r
703         mov     ebx,[auxiliary_output_areas]\r
704         mov     edi,write_auxiliary_output_area\r
705         call    iterate_through_map\r
706         cmp     [output_failures],0\r
707         jne     output_write_failed\r
708         clc\r
709         retn\r
710     file_write_failed:\r
711         call    close\r
712     output_write_failed:\r
713         stc\r
714         retn\r
716 write_auxiliary_output_area:\r
717 ; in:\r
718 ;  eax = ValueDefinition, null for cached extension not used for auxiliary output\r
719 ;  esi - file extension\r
720 ;  ecx = length of the extension\r
721         test    eax,eax\r
722         jz      auxiliary_output_processed\r
723         mov     ebx,[base_path]\r
724         test    ebx,ebx\r
725         jz      auxiliary_output_processed\r
726         push    eax\r
727         call    create_output_path\r
728         call    create\r
729         pop     edx\r
730         jc      auxiliary_file_creation_failed\r
731         mov     eax,[edx+ValueDefinition.value]\r
732         mov     ecx,[edx+ValueDefinition.value_length]\r
733         mov     edx,[eax+AreaHeader.base_address_length]\r
734         add     edx,sizeof.AreaHeader\r
735         sub     ecx,edx\r
736         add     edx,eax\r
737         call    write\r
738         jc      auxiliary_file_write_failed\r
739         call    close\r
740     auxiliary_output_processed:\r
741         retn\r
742     auxiliary_file_write_failed:\r
743         call    close\r
744     auxiliary_file_creation_failed:\r
745         inc     [output_failures]\r
746         retn\r