1 1.1 christos ; match686.asm -- Asm portion of the optimized longest_match for 32 bits x86 2 1.1 christos ; Copyright (C) 1995-1996 Jean-loup Gailly, Brian Raiter and Gilles Vollant. 3 1.1 christos ; File written by Gilles Vollant, by converting match686.S from Brian Raiter 4 1.1 christos ; for MASM. This is as assembly version of longest_match 5 1.1 christos ; from Jean-loup Gailly in deflate.c 6 1.1 christos ; 7 1.1 christos ; http://www.zlib.net 8 1.1 christos ; http://www.winimage.com/zLibDll 9 1.1 christos ; http://www.muppetlabs.com/~breadbox/software/assembly.html 10 1.1 christos ; 11 1.1 christos ; For Visual C++ 4.x and higher and ML 6.x and higher 12 1.1 christos ; ml.exe is distributed in 13 1.1 christos ; http://www.microsoft.com/downloads/details.aspx?FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 14 1.1 christos ; 15 1.1 christos ; this file contain two implementation of longest_match 16 1.1 christos ; 17 1.1 christos ; this longest_match was written by Brian raiter (1998), optimized for Pentium Pro 18 1.1 christos ; (and the faster known version of match_init on modern Core 2 Duo and AMD Phenom) 19 1.1 christos ; 20 1.1 christos ; for using an assembly version of longest_match, you need define ASMV in project 21 1.1 christos ; 22 1.1 christos ; compile the asm file running 23 1.1 christos ; ml /coff /Zi /c /Flmatch686.lst match686.asm 24 1.1 christos ; and do not include match686.obj in your project 25 1.1 christos ; 26 1.1 christos ; note: contrib of zLib 1.2.3 and earlier contained both a deprecated version for 27 1.1 christos ; Pentium (prior Pentium Pro) and this version for Pentium Pro and modern processor 28 1.1 christos ; with autoselect (with cpu detection code) 29 1.1 christos ; if you want support the old pentium optimization, you can still use these version 30 1.1 christos ; 31 1.1 christos ; this file is not optimized for old pentium, but it compatible with all x86 32 bits 32 1.1 christos ; processor (starting 80386) 33 1.1 christos ; 34 1.1 christos ; 35 1.1 christos ; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2 36 1.1 christos 37 1.1 christos ;uInt longest_match(s, cur_match) 38 1.1 christos ; deflate_state *s; 39 1.1 christos ; IPos cur_match; /* current match */ 40 1.1 christos 41 1.1 christos NbStack equ 76 42 1.1 christos cur_match equ dword ptr[esp+NbStack-0] 43 1.1 christos str_s equ dword ptr[esp+NbStack-4] 44 1.1 christos ; 5 dword on top (ret,ebp,esi,edi,ebx) 45 1.1 christos adrret equ dword ptr[esp+NbStack-8] 46 1.1 christos pushebp equ dword ptr[esp+NbStack-12] 47 1.1 christos pushedi equ dword ptr[esp+NbStack-16] 48 1.1 christos pushesi equ dword ptr[esp+NbStack-20] 49 1.1 christos pushebx equ dword ptr[esp+NbStack-24] 50 1.1 christos 51 1.1 christos chain_length equ dword ptr [esp+NbStack-28] 52 1.1 christos limit equ dword ptr [esp+NbStack-32] 53 1.1 christos best_len equ dword ptr [esp+NbStack-36] 54 1.1 christos window equ dword ptr [esp+NbStack-40] 55 1.1 christos prev equ dword ptr [esp+NbStack-44] 56 1.1 christos scan_start equ word ptr [esp+NbStack-48] 57 1.1 christos wmask equ dword ptr [esp+NbStack-52] 58 1.1 christos match_start_ptr equ dword ptr [esp+NbStack-56] 59 1.1 christos nice_match equ dword ptr [esp+NbStack-60] 60 1.1 christos scan equ dword ptr [esp+NbStack-64] 61 1.1 christos 62 1.1 christos windowlen equ dword ptr [esp+NbStack-68] 63 1.1 christos match_start equ dword ptr [esp+NbStack-72] 64 1.1 christos strend equ dword ptr [esp+NbStack-76] 65 1.1 christos NbStackAdd equ (NbStack-24) 66 1.1 christos 67 1.1 christos .386p 68 1.1 christos 69 1.1 christos name gvmatch 70 1.1 christos .MODEL FLAT 71 1.1 christos 72 1.1 christos 73 1.1 christos 74 1.1 christos ; all the +zlib1222add offsets are due to the addition of fields 75 1.1 christos ; in zlib in the deflate_state structure since the asm code was first written 76 1.1 christos ; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). 77 1.1 christos ; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). 78 1.1 christos ; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). 79 1.1 christos 80 1.1 christos zlib1222add equ 8 81 1.1 christos 82 1.1 christos ; Note : these value are good with a 8 bytes boundary pack structure 83 1.1 christos dep_chain_length equ 74h+zlib1222add 84 1.1 christos dep_window equ 30h+zlib1222add 85 1.1 christos dep_strstart equ 64h+zlib1222add 86 1.1 christos dep_prev_length equ 70h+zlib1222add 87 1.1 christos dep_nice_match equ 88h+zlib1222add 88 1.1 christos dep_w_size equ 24h+zlib1222add 89 1.1 christos dep_prev equ 38h+zlib1222add 90 1.1 christos dep_w_mask equ 2ch+zlib1222add 91 1.1 christos dep_good_match equ 84h+zlib1222add 92 1.1 christos dep_match_start equ 68h+zlib1222add 93 1.1 christos dep_lookahead equ 6ch+zlib1222add 94 1.1 christos 95 1.1 christos 96 1.1 christos _TEXT segment 97 1.1 christos 98 1.1 christos IFDEF NOUNDERLINE 99 1.1 christos public longest_match 100 1.1 christos public match_init 101 1.1 christos ELSE 102 1.1 christos public _longest_match 103 1.1 christos public _match_init 104 1.1 christos ENDIF 105 1.1 christos 106 1.1 christos MAX_MATCH equ 258 107 1.1 christos MIN_MATCH equ 3 108 1.1 christos MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) 109 1.1 christos 110 1.1 christos 111 1.1 christos 112 1.1 christos MAX_MATCH equ 258 113 1.1 christos MIN_MATCH equ 3 114 1.1 christos MIN_LOOKAHEAD equ (MAX_MATCH + MIN_MATCH + 1) 115 1.1 christos MAX_MATCH_8_ equ ((MAX_MATCH + 7) AND 0FFF0h) 116 1.1 christos 117 1.1 christos 118 1.1 christos ;;; stack frame offsets 119 1.1 christos 120 1.1 christos chainlenwmask equ esp + 0 ; high word: current chain len 121 1.1 christos ; low word: s->wmask 122 1.1 christos window equ esp + 4 ; local copy of s->window 123 1.1 christos windowbestlen equ esp + 8 ; s->window + bestlen 124 1.1 christos scanstart equ esp + 16 ; first two bytes of string 125 1.1 christos scanend equ esp + 12 ; last two bytes of string 126 1.1 christos scanalign equ esp + 20 ; dword-misalignment of string 127 1.1 christos nicematch equ esp + 24 ; a good enough match size 128 1.1 christos bestlen equ esp + 28 ; size of best match so far 129 1.1 christos scan equ esp + 32 ; ptr to string wanting match 130 1.1 christos 131 1.1 christos LocalVarsSize equ 36 132 1.1 christos ; saved ebx byte esp + 36 133 1.1 christos ; saved edi byte esp + 40 134 1.1 christos ; saved esi byte esp + 44 135 1.1 christos ; saved ebp byte esp + 48 136 1.1 christos ; return address byte esp + 52 137 1.1 christos deflatestate equ esp + 56 ; the function arguments 138 1.1 christos curmatch equ esp + 60 139 1.1 christos 140 1.1 christos ;;; Offsets for fields in the deflate_state structure. These numbers 141 1.1 christos ;;; are calculated from the definition of deflate_state, with the 142 1.1 christos ;;; assumption that the compiler will dword-align the fields. (Thus, 143 1.1 christos ;;; changing the definition of deflate_state could easily cause this 144 1.1 christos ;;; program to crash horribly, without so much as a warning at 145 1.1 christos ;;; compile time. Sigh.) 146 1.1 christos 147 1.1 christos dsWSize equ 36+zlib1222add 148 1.1 christos dsWMask equ 44+zlib1222add 149 1.1 christos dsWindow equ 48+zlib1222add 150 1.1 christos dsPrev equ 56+zlib1222add 151 1.1 christos dsMatchLen equ 88+zlib1222add 152 1.1 christos dsPrevMatch equ 92+zlib1222add 153 1.1 christos dsStrStart equ 100+zlib1222add 154 1.1 christos dsMatchStart equ 104+zlib1222add 155 1.1 christos dsLookahead equ 108+zlib1222add 156 1.1 christos dsPrevLen equ 112+zlib1222add 157 1.1 christos dsMaxChainLen equ 116+zlib1222add 158 1.1 christos dsGoodMatch equ 132+zlib1222add 159 1.1 christos dsNiceMatch equ 136+zlib1222add 160 1.1 christos 161 1.1 christos 162 1.1 christos ;;; match686.asm -- Pentium-Pro-optimized version of longest_match() 163 1.1 christos ;;; Written for zlib 1.1.2 164 1.1 christos ;;; Copyright (C) 1998 Brian Raiter <breadbox (a] muppetlabs.com> 165 1.1 christos ;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html 166 1.1 christos ;;; 167 1.1 christos ;; 168 1.1 christos ;; This software is provided 'as-is', without any express or implied 169 1.1 christos ;; warranty. In no event will the authors be held liable for any damages 170 1.1 christos ;; arising from the use of this software. 171 1.1 christos ;; 172 1.1 christos ;; Permission is granted to anyone to use this software for any purpose, 173 1.1 christos ;; including commercial applications, and to alter it and redistribute it 174 1.1 christos ;; freely, subject to the following restrictions: 175 1.1 christos ;; 176 1.1 christos ;; 1. The origin of this software must not be misrepresented; you must not 177 1.1 christos ;; claim that you wrote the original software. If you use this software 178 1.1 christos ;; in a product, an acknowledgment in the product documentation would be 179 1.1 christos ;; appreciated but is not required. 180 1.1 christos ;; 2. Altered source versions must be plainly marked as such, and must not be 181 1.1 christos ;; misrepresented as being the original software 182 1.1 christos ;; 3. This notice may not be removed or altered from any source distribution. 183 1.1 christos ;; 184 1.1 christos 185 1.1 christos ;GLOBAL _longest_match, _match_init 186 1.1 christos 187 1.1 christos 188 1.1 christos ;SECTION .text 189 1.1 christos 190 1.1 christos ;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch) 191 1.1 christos 192 1.1 christos ;_longest_match: 193 1.1 christos IFDEF NOUNDERLINE 194 1.1 christos longest_match proc near 195 1.1 christos ELSE 196 1.1 christos _longest_match proc near 197 1.1 christos ENDIF 198 1.1 christos .FPO (9, 4, 0, 0, 1, 0) 199 1.1 christos 200 1.1 christos ;;; Save registers that the compiler may be using, and adjust esp to 201 1.1 christos ;;; make room for our stack frame. 202 1.1 christos 203 1.1 christos push ebp 204 1.1 christos push edi 205 1.1 christos push esi 206 1.1 christos push ebx 207 1.1 christos sub esp, LocalVarsSize 208 1.1 christos 209 1.1 christos ;;; Retrieve the function arguments. ecx will hold cur_match 210 1.1 christos ;;; throughout the entire function. edx will hold the pointer to the 211 1.1 christos ;;; deflate_state structure during the function's setup (before 212 1.1 christos ;;; entering the main loop. 213 1.1 christos 214 1.1 christos mov edx, [deflatestate] 215 1.1 christos mov ecx, [curmatch] 216 1.1 christos 217 1.1 christos ;;; uInt wmask = s->w_mask; 218 1.1 christos ;;; unsigned chain_length = s->max_chain_length; 219 1.1 christos ;;; if (s->prev_length >= s->good_match) { 220 1.1 christos ;;; chain_length >>= 2; 221 1.1 christos ;;; } 222 1.1 christos 223 1.1 christos mov eax, [edx + dsPrevLen] 224 1.1 christos mov ebx, [edx + dsGoodMatch] 225 1.1 christos cmp eax, ebx 226 1.1 christos mov eax, [edx + dsWMask] 227 1.1 christos mov ebx, [edx + dsMaxChainLen] 228 1.1 christos jl LastMatchGood 229 1.1 christos shr ebx, 2 230 1.1 christos LastMatchGood: 231 1.1 christos 232 1.1 christos ;;; chainlen is decremented once beforehand so that the function can 233 1.1 christos ;;; use the sign flag instead of the zero flag for the exit test. 234 1.1 christos ;;; It is then shifted into the high word, to make room for the wmask 235 1.1 christos ;;; value, which it will always accompany. 236 1.1 christos 237 1.1 christos dec ebx 238 1.1 christos shl ebx, 16 239 1.1 christos or ebx, eax 240 1.1 christos mov [chainlenwmask], ebx 241 1.1 christos 242 1.1 christos ;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; 243 1.1 christos 244 1.1 christos mov eax, [edx + dsNiceMatch] 245 1.1 christos mov ebx, [edx + dsLookahead] 246 1.1 christos cmp ebx, eax 247 1.1 christos jl LookaheadLess 248 1.1 christos mov ebx, eax 249 1.1 christos LookaheadLess: mov [nicematch], ebx 250 1.1 christos 251 1.1 christos ;;; register Bytef *scan = s->window + s->strstart; 252 1.1 christos 253 1.1 christos mov esi, [edx + dsWindow] 254 1.1 christos mov [window], esi 255 1.1 christos mov ebp, [edx + dsStrStart] 256 1.1 christos lea edi, [esi + ebp] 257 1.1 christos mov [scan], edi 258 1.1 christos 259 1.1 christos ;;; Determine how many bytes the scan ptr is off from being 260 1.1 christos ;;; dword-aligned. 261 1.1 christos 262 1.1 christos mov eax, edi 263 1.1 christos neg eax 264 1.1 christos and eax, 3 265 1.1 christos mov [scanalign], eax 266 1.1 christos 267 1.1 christos ;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? 268 1.1 christos ;;; s->strstart - (IPos)MAX_DIST(s) : NIL; 269 1.1 christos 270 1.1 christos mov eax, [edx + dsWSize] 271 1.1 christos sub eax, MIN_LOOKAHEAD 272 1.1 christos sub ebp, eax 273 1.1 christos jg LimitPositive 274 1.1 christos xor ebp, ebp 275 1.1 christos LimitPositive: 276 1.1 christos 277 1.1 christos ;;; int best_len = s->prev_length; 278 1.1 christos 279 1.1 christos mov eax, [edx + dsPrevLen] 280 1.1 christos mov [bestlen], eax 281 1.1 christos 282 1.1 christos ;;; Store the sum of s->window + best_len in esi locally, and in esi. 283 1.1 christos 284 1.1 christos add esi, eax 285 1.1 christos mov [windowbestlen], esi 286 1.1 christos 287 1.1 christos ;;; register ush scan_start = *(ushf*)scan; 288 1.1 christos ;;; register ush scan_end = *(ushf*)(scan+best_len-1); 289 1.1 christos ;;; Posf *prev = s->prev; 290 1.1 christos 291 1.1 christos movzx ebx, word ptr [edi] 292 1.1 christos mov [scanstart], ebx 293 1.1 christos movzx ebx, word ptr [edi + eax - 1] 294 1.1 christos mov [scanend], ebx 295 1.1 christos mov edi, [edx + dsPrev] 296 1.1 christos 297 1.1 christos ;;; Jump into the main loop. 298 1.1 christos 299 1.1 christos mov edx, [chainlenwmask] 300 1.1 christos jmp short LoopEntry 301 1.1 christos 302 1.1 christos align 4 303 1.1 christos 304 1.1 christos ;;; do { 305 1.1 christos ;;; match = s->window + cur_match; 306 1.1 christos ;;; if (*(ushf*)(match+best_len-1) != scan_end || 307 1.1 christos ;;; *(ushf*)match != scan_start) continue; 308 1.1 christos ;;; [...] 309 1.1 christos ;;; } while ((cur_match = prev[cur_match & wmask]) > limit 310 1.1 christos ;;; && --chain_length != 0); 311 1.1 christos ;;; 312 1.1 christos ;;; Here is the inner loop of the function. The function will spend the 313 1.1 christos ;;; majority of its time in this loop, and majority of that time will 314 1.1 christos ;;; be spent in the first ten instructions. 315 1.1 christos ;;; 316 1.1 christos ;;; Within this loop: 317 1.1 christos ;;; ebx = scanend 318 1.1 christos ;;; ecx = curmatch 319 1.1 christos ;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) 320 1.1 christos ;;; esi = windowbestlen - i.e., (window + bestlen) 321 1.1 christos ;;; edi = prev 322 1.1 christos ;;; ebp = limit 323 1.1 christos 324 1.1 christos LookupLoop: 325 1.1 christos and ecx, edx 326 1.1 christos movzx ecx, word ptr [edi + ecx*2] 327 1.1 christos cmp ecx, ebp 328 1.1 christos jbe LeaveNow 329 1.1 christos sub edx, 00010000h 330 1.1 christos js LeaveNow 331 1.1 christos LoopEntry: movzx eax, word ptr [esi + ecx - 1] 332 1.1 christos cmp eax, ebx 333 1.1 christos jnz LookupLoop 334 1.1 christos mov eax, [window] 335 1.1 christos movzx eax, word ptr [eax + ecx] 336 1.1 christos cmp eax, [scanstart] 337 1.1 christos jnz LookupLoop 338 1.1 christos 339 1.1 christos ;;; Store the current value of chainlen. 340 1.1 christos 341 1.1 christos mov [chainlenwmask], edx 342 1.1 christos 343 1.1 christos ;;; Point edi to the string under scrutiny, and esi to the string we 344 1.1 christos ;;; are hoping to match it up with. In actuality, esi and edi are 345 1.1 christos ;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is 346 1.1 christos ;;; initialized to -(MAX_MATCH_8 - scanalign). 347 1.1 christos 348 1.1 christos mov esi, [window] 349 1.1 christos mov edi, [scan] 350 1.1 christos add esi, ecx 351 1.1 christos mov eax, [scanalign] 352 1.1 christos mov edx, 0fffffef8h; -(MAX_MATCH_8) 353 1.1 christos lea edi, [edi + eax + 0108h] ;MAX_MATCH_8] 354 1.1 christos lea esi, [esi + eax + 0108h] ;MAX_MATCH_8] 355 1.1 christos 356 1.1 christos ;;; Test the strings for equality, 8 bytes at a time. At the end, 357 1.1 christos ;;; adjust edx so that it is offset to the exact byte that mismatched. 358 1.1 christos ;;; 359 1.1 christos ;;; We already know at this point that the first three bytes of the 360 1.1 christos ;;; strings match each other, and they can be safely passed over before 361 1.1 christos ;;; starting the compare loop. So what this code does is skip over 0-3 362 1.1 christos ;;; bytes, as much as necessary in order to dword-align the edi 363 1.1 christos ;;; pointer. (esi will still be misaligned three times out of four.) 364 1.1 christos ;;; 365 1.1 christos ;;; It should be confessed that this loop usually does not represent 366 1.1 christos ;;; much of the total running time. Replacing it with a more 367 1.1 christos ;;; straightforward "rep cmpsb" would not drastically degrade 368 1.1 christos ;;; performance. 369 1.1 christos 370 1.1 christos LoopCmps: 371 1.1 christos mov eax, [esi + edx] 372 1.1 christos xor eax, [edi + edx] 373 1.1 christos jnz LeaveLoopCmps 374 1.1 christos mov eax, [esi + edx + 4] 375 1.1 christos xor eax, [edi + edx + 4] 376 1.1 christos jnz LeaveLoopCmps4 377 1.1 christos add edx, 8 378 1.1 christos jnz LoopCmps 379 1.1 christos jmp short LenMaximum 380 1.1 christos LeaveLoopCmps4: add edx, 4 381 1.1 christos LeaveLoopCmps: test eax, 0000FFFFh 382 1.1 christos jnz LenLower 383 1.1 christos add edx, 2 384 1.1 christos shr eax, 16 385 1.1 christos LenLower: sub al, 1 386 1.1 christos adc edx, 0 387 1.1 christos 388 1.1 christos ;;; Calculate the length of the match. If it is longer than MAX_MATCH, 389 1.1 christos ;;; then automatically accept it as the best possible match and leave. 390 1.1 christos 391 1.1 christos lea eax, [edi + edx] 392 1.1 christos mov edi, [scan] 393 1.1 christos sub eax, edi 394 1.1 christos cmp eax, MAX_MATCH 395 1.1 christos jge LenMaximum 396 1.1 christos 397 1.1 christos ;;; If the length of the match is not longer than the best match we 398 1.1 christos ;;; have so far, then forget it and return to the lookup loop. 399 1.1 christos 400 1.1 christos mov edx, [deflatestate] 401 1.1 christos mov ebx, [bestlen] 402 1.1 christos cmp eax, ebx 403 1.1 christos jg LongerMatch 404 1.1 christos mov esi, [windowbestlen] 405 1.1 christos mov edi, [edx + dsPrev] 406 1.1 christos mov ebx, [scanend] 407 1.1 christos mov edx, [chainlenwmask] 408 1.1 christos jmp LookupLoop 409 1.1 christos 410 1.1 christos ;;; s->match_start = cur_match; 411 1.1 christos ;;; best_len = len; 412 1.1 christos ;;; if (len >= nice_match) break; 413 1.1 christos ;;; scan_end = *(ushf*)(scan+best_len-1); 414 1.1 christos 415 1.1 christos LongerMatch: mov ebx, [nicematch] 416 1.1 christos mov [bestlen], eax 417 1.1 christos mov [edx + dsMatchStart], ecx 418 1.1 christos cmp eax, ebx 419 1.1 christos jge LeaveNow 420 1.1 christos mov esi, [window] 421 1.1 christos add esi, eax 422 1.1 christos mov [windowbestlen], esi 423 1.1 christos movzx ebx, word ptr [edi + eax - 1] 424 1.1 christos mov edi, [edx + dsPrev] 425 1.1 christos mov [scanend], ebx 426 1.1 christos mov edx, [chainlenwmask] 427 1.1 christos jmp LookupLoop 428 1.1 christos 429 1.1 christos ;;; Accept the current string, with the maximum possible length. 430 1.1 christos 431 1.1 christos LenMaximum: mov edx, [deflatestate] 432 1.1 christos mov dword ptr [bestlen], MAX_MATCH 433 1.1 christos mov [edx + dsMatchStart], ecx 434 1.1 christos 435 1.1 christos ;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; 436 1.1 christos ;;; return s->lookahead; 437 1.1 christos 438 1.1 christos LeaveNow: 439 1.1 christos mov edx, [deflatestate] 440 1.1 christos mov ebx, [bestlen] 441 1.1 christos mov eax, [edx + dsLookahead] 442 1.1 christos cmp ebx, eax 443 1.1 christos jg LookaheadRet 444 1.1 christos mov eax, ebx 445 1.1 christos LookaheadRet: 446 1.1 christos 447 1.1 christos ;;; Restore the stack and return from whence we came. 448 1.1 christos 449 1.1 christos add esp, LocalVarsSize 450 1.1 christos pop ebx 451 1.1 christos pop esi 452 1.1 christos pop edi 453 1.1 christos pop ebp 454 1.1 christos 455 1.1 christos ret 456 1.1 christos ; please don't remove this string ! 457 1.1 christos ; Your can freely use match686 in any free or commercial app if you don't remove the string in the binary! 458 1.1 christos db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah 459 1.1 christos 460 1.1 christos 461 1.1 christos IFDEF NOUNDERLINE 462 1.1 christos longest_match endp 463 1.1 christos ELSE 464 1.1 christos _longest_match endp 465 1.1 christos ENDIF 466 1.1 christos 467 1.1 christos IFDEF NOUNDERLINE 468 1.1 christos match_init proc near 469 1.1 christos ret 470 1.1 christos match_init endp 471 1.1 christos ELSE 472 1.1 christos _match_init proc near 473 1.1 christos ret 474 1.1 christos _match_init endp 475 1.1 christos ENDIF 476 1.1 christos 477 1.1 christos 478 1.1 christos _TEXT ends 479 1.1 christos end 480