From 2f6bca29f2e17a161feca2da0e81de26f97b3d8b Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sat, 16 Sep 2006 01:36:58 +0000 Subject: [PATCH] * section.c (yasm_object_optimize): Set active flag to indicate it's already on QB. We use this flag other places, but forgot to set it here. This could cause an infinite loop in (rare) situations. Reported by: Brian Gladman (also committed the code he sent that hits this bug as a testcase) svn path=/trunk/yasm/; revision=1613 --- libyasm/section.c | 1 + libyasm/tests/Makefile.inc | 3 + libyasm/tests/opt-gvmat64.asm | 514 +++++++++++++++++++++ libyasm/tests/opt-gvmat64.errwarn | 0 libyasm/tests/opt-gvmat64.hex | 731 ++++++++++++++++++++++++++++++ 5 files changed, 1249 insertions(+) create mode 100644 libyasm/tests/opt-gvmat64.asm create mode 100644 libyasm/tests/opt-gvmat64.errwarn create mode 100644 libyasm/tests/opt-gvmat64.hex diff --git a/libyasm/section.c b/libyasm/section.c index 78f79ece..faa4396d 100644 --- a/libyasm/section.c +++ b/libyasm/section.c @@ -1296,6 +1296,7 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, if (recalc_normal_span(span)) { /* Exceeded threshold, add span to QB */ STAILQ_INSERT_TAIL(&optd.QB, span, linkq); + span->active = 2; } } diff --git a/libyasm/tests/Makefile.inc b/libyasm/tests/Makefile.inc index 7f1607cc..03ea1476 100644 --- a/libyasm/tests/Makefile.inc +++ b/libyasm/tests/Makefile.inc @@ -47,6 +47,9 @@ EXTRA_DIST += libyasm/tests/opt-circular2-err.asm EXTRA_DIST += libyasm/tests/opt-circular2-err.errwarn EXTRA_DIST += libyasm/tests/opt-circular3-err.asm EXTRA_DIST += libyasm/tests/opt-circular3-err.errwarn +EXTRA_DIST += libyasm/tests/opt-gvmat64.asm +EXTRA_DIST += libyasm/tests/opt-gvmat64.errwarn +EXTRA_DIST += libyasm/tests/opt-gvmat64.hex EXTRA_DIST += libyasm/tests/opt-immexpand.asm EXTRA_DIST += libyasm/tests/opt-immexpand.errwarn EXTRA_DIST += libyasm/tests/opt-immexpand.hex diff --git a/libyasm/tests/opt-gvmat64.asm b/libyasm/tests/opt-gvmat64.asm new file mode 100644 index 00000000..35ac7ac9 --- /dev/null +++ b/libyasm/tests/opt-gvmat64.asm @@ -0,0 +1,514 @@ +;uInt longest_match_x64( +; deflate_state *s, +; IPos cur_match); /* current match */ + +; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86 +; Copyright (C) 1995-2005 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; +; File written by Gilles Vollant, by converting to assembly the longest_match +; from Jean-loup Gailly in deflate.c of zLib and infoZip zip. +; +; and by taking inspiration on asm686 with masm, optimised assembly code +; from Brian Raiter, written 1998 +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; to compile this file for infozip Zip, I use option: +; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm +; +; to compile this file for zLib, I use option: +; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm +; Be carrefull to adapt zlib1222add below to your version of zLib +; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change +; value of zlib1222add later) +; +; This file compile with Microsoft Macro Assembler (x64) for AMD64 +; +; ml64.exe is given with Visual Studio 2005 and Windows 2003 server DDK +; +; (you can get Windows 2003 server DDK with ml64 and cl for AMD64 from +; http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price) +; + + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; /* current match */ +bits 64 + section .text + +longest_match: ; PROC + + +;%define LocalVarsSize 88 + %define LocalVarsSize 72 + +; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 +; free register : r14,r15 +; register can be saved : rsp + + %define chainlenwmask rsp + 8 - LocalVarsSize ; high word: current chain len + ; low word: s->wmask +;%define window rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10 +;%define windowbestlen rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11 +;%define scanstart rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w +;%define scanend rsp + xx - LocalVarsSize ; last two bytes of string use ebx +;%define scanalign rsp + xx - LocalVarsSize ; dword-misalignment of string r13 +;%define bestlen rsp + xx - LocalVarsSize ; size of best match so far -> r11d +;%define scan rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9 +%ifdef INFOZIP +%else + %define nicematch (rsp + 16 - LocalVarsSize) ; a good enough match size +%endif + +%define save_rdi rsp + 24 - LocalVarsSize +%define save_rsi rsp + 32 - LocalVarsSize +%define save_rbx rsp + 40 - LocalVarsSize +%define save_rbp rsp + 48 - LocalVarsSize +%define save_r12 rsp + 56 - LocalVarsSize +%define save_r13 rsp + 64 - LocalVarsSize +;%define save_r14 rsp + 72 - LocalVarsSize +;%define save_r15 rsp + 80 - LocalVarsSize + + + +; all the +4 offsets are due to the addition of pending_buf_size (in zlib +; in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, remove the +4). +; Note : these value are good with a 8 bytes boundary pack structure + + + %define MAX_MATCH 258 + %define MIN_MATCH 3 + %define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) + + +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "%define zlib1222add (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "%define zlib1222add 0"). +; if you compile with zlib 1.2.2.2 or later , use "%define zlib1222add 8"). + +%ifdef INFOZIP + section .data + +extern window_size:DWORD +; WMask ; 7fff +extern window:BYTE:010040H +extern prev:WORD:08000H +; MatchLen : unused +; PrevMatch : unused +extern strstart:DWORD +extern match_start:DWORD +; Lookahead : ignore +extern prev_length:DWORD ; PrevLen +extern max_chain_length:DWORD +extern good_match:DWORD +extern nice_match:DWORD +%define prev_ad OFFSET prev +%define window_ad OFFSET window +%define nicematch nice_match + +%define WMask 07fffh + +%else + + %ifndef zlib1222add + %define zlib1222add 8 + %endif +%define dsWSize 56+zlib1222add+(zlib1222add/2) +%define dsWMask 64+zlib1222add+(zlib1222add/2) +%define dsWindow 72+zlib1222add +%define dsPrev 88+zlib1222add +%define dsMatchLen 128+zlib1222add +%define dsPrevMatch 132+zlib1222add +%define dsStrStart 140+zlib1222add +%define dsMatchStart 144+zlib1222add +%define dsLookahead 148+zlib1222add +%define dsPrevLen 152+zlib1222add +%define dsMaxChainLen 156+zlib1222add +%define dsGoodMatch 172+zlib1222add +%define dsNiceMatch 176+zlib1222add + +%define window_size [ rcx + dsWSize] +%define WMask [ rcx + dsWMask] +%define window_ad [ rcx + dsWindow] +%define prev_ad [ rcx + dsPrev] +%define strstart [ rcx + dsStrStart] +%define match_start [ rcx + dsMatchStart] +%define Lookahead [ rcx + dsLookahead] ; 0ffffffffh on infozip +%define prev_length [ rcx + dsPrevLen] +%define max_chain_length [ rcx + dsMaxChainLen] +%define good_match [ rcx + dsGoodMatch] +%define nice_match [ rcx + dsNiceMatch] +%endif + +; parameter 1 in r8(deflate state s), param 2 in rdx (cur match) + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch. + + section .text + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + +;;; Retrieve the function arguments. r8d will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + +; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) + +; this clear high 32 bits of r8, which can be garbage in both r8 and rdx + + mov [save_rdi],rdi + mov [save_rsi],rsi + mov [save_rbx],rbx + mov [save_rbp],rbp +%ifdef INFOZIP + mov r8d,ecx +%else + mov r8d,edx +%endif + mov [save_r12],r12 + mov [save_r13],r13 +; mov [save_r14],r14 +; mov [save_r15],r15 + + +;;; uInt wmask = s->w_mask; +;;; unsigned chain_length = s->max_chain_length; +;;; if (s->prev_length >= s->good_match) { +;;; chain_length >>= 2; +;;; } + + mov edi, prev_length + mov esi, good_match + mov eax, WMask + mov ebx, max_chain_length + cmp edi, esi + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +;;; chainlen is decremented once beforehand so that the function can +;;; use the sign flag instead of the zero flag for the exit test. +;;; It is then shifted into the high word, to make room for the wmask +;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + +;;; on zlib only +;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + +%ifdef INFOZIP + mov [chainlenwmask], ebx +; on infozip nice_match = [nice_match] +%else + mov eax, nice_match + mov [chainlenwmask], ebx + mov r10d, Lookahead + cmp r10d, eax + cmovnl r10d, eax + mov [nicematch],r10d +%endif + +;;; register Bytef *scan = s->window + s->strstart; + mov r10, window_ad + mov ebp, strstart + lea r13, [r10 + rbp] + +;;; Determine how many bytes the scan ptr is off from being +;;; dword-aligned. + + mov r9,r13 + neg r13 + and r13,3 + +;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +;;; s->strstart - (IPos)MAX_DIST(s) : NIL; +%ifdef INFOZIP + mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1)) +%else + mov eax, window_size + sub eax, MIN_LOOKAHEAD +%endif + xor edi,edi + sub ebp, eax + + mov r11d, prev_length + + cmovng ebp,edi + +;;; int best_len = s->prev_length; + + +;;; Store the sum of s->window + best_len in esi locally, and in esi. + + lea rsi,[r10+r11] + +;;; register ush scan_start = *(ushf*)scan; +;;; register ush scan_end = *(ushf*)(scan+best_len-1); +;;; Posf *prev = s->prev; + + movzx r12d,word [r9] + movzx ebx, word [r9 + r11 - 1] + + mov rdi, prev_ad + +;;; Jump into the main loop. + + mov edx, [chainlenwmask] + + cmp bx,word [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop1: + and r8d, edx + + movzx r8d, word [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry1: + cmp bx,word [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop2: + and r8d, edx + + movzx r8d, word [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry2: + cmp bx,word [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop4: + and r8d, edx + + movzx r8d, word [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry4: + + cmp bx,word [rsi + r8 - 1] + jnz LookupLoop1 + jmp LookupLoopIsZero + + +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; r8d = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit + +LookupLoop: + and r8d, edx + + movzx r8d, word [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry: + + cmp bx,word [rsi + r8 - 1] + jnz LookupLoop1 +LookupLoopIsZero: + cmp r12w, word [r10 + r8] + jnz LookupLoop1 + + +;;; Store the current value of chainlen. + mov [chainlenwmask], edx + +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). + + lea rsi,[r8+r10] + mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8) + lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8] + lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8] + + prefetcht1 [rsi+rdx] + prefetcht1 [rdi+rdx] + + +;;; Test the strings %define for ality, 8 bytes at a time. At the end, +;;; adjust rdx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (rsi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. + +LoopCmps: + mov rax, [rsi + rdx] + xor rax, [rdi + rdx] + jnz LeaveLoopCmps + + mov rax, [rsi + rdx + 8] + xor rax, [rdi + rdx + 8] + jnz LeaveLoopCmps8 + + + mov rax, [rsi + rdx + 8+8] + xor rax, [rdi + rdx + 8+8] + jnz LeaveLoopCmps16 + + add rdx,8+8+8 + + jmp short LoopCmps +LeaveLoopCmps16: add rdx,8 +LeaveLoopCmps8: add rdx,8 +LeaveLoopCmps: + + test eax, 0000FFFFh + jnz LenLower + + test eax,0ffffffffh + + jnz LenLower32 + + add rdx,4 + shr rax,32 + or ax,ax + jnz LenLower + +LenLower32: + shr eax,16 + add rdx,2 +LenLower: sub al, 1 + adc rdx, 0 +;;; Calculate the length of the match. If it is longer than MAX_MATCH, +;;; then automatically accept it as the best possible match and leave. + + lea rax, [rdi + rdx] + sub rax, r9 + cmp eax, MAX_MATCH + jge LenMaximum + +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. +;/////////////////////////////////// + + cmp eax, r11d + jg LongerMatch + + lea rsi,[r10+r11] + + mov rdi, prev_ad + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); + +LongerMatch: + mov r11d, eax + mov match_start, r8d + cmp eax, [nicematch] + jge LeaveNow + + lea rsi,[r10+rax] + + movzx ebx, word [r9 + rax - 1] + mov rdi, prev_ad + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; Accept the current string, with the maximum possible length. + +LenMaximum: + mov r11d,MAX_MATCH + mov match_start, r8d +;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +;;; return s->lookahead; + +LeaveNow: +%ifdef INFOZIP + mov eax,r11d +%else + mov eax, Lookahead + cmp r11d, eax + cmovng eax, r11d +%endif + +;;; Restore the stack and return from whence we came. + + mov rsi,[save_rsi] + mov rdi,[save_rdi] + mov rbx,[save_rbx] + mov rbp,[save_rbp] + mov r12,[save_r12] + mov r13,[save_r13] +; mov r14,[save_r14] +; mov r15,[save_r15] + + + ret 0 +; please don't remove this string ! +; Your can freely use gvmat64 in any free or externercial app +; but it is far better don't remove the string in the binary! + db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 +%if 0 +longest_match ENDP +%endif + +match_init: ; PROC + ret 0 + %if 0 +match_init ENDP +%endif + +END diff --git a/libyasm/tests/opt-gvmat64.errwarn b/libyasm/tests/opt-gvmat64.errwarn new file mode 100644 index 00000000..e69de29b diff --git a/libyasm/tests/opt-gvmat64.hex b/libyasm/tests/opt-gvmat64.hex new file mode 100644 index 00000000..b2432d6a --- /dev/null +++ b/libyasm/tests/opt-gvmat64.hex @@ -0,0 +1,731 @@ +48 +89 +7c +24 +d0 +48 +89 +74 +24 +d8 +48 +89 +5c +24 +e0 +48 +89 +6c +24 +e8 +41 +89 +d0 +4c +89 +64 +24 +f0 +4c +89 +6c +24 +f8 +8b +b9 +a0 +00 +00 +00 +8b +b1 +b4 +00 +00 +00 +8b +41 +4c +8b +99 +a4 +00 +00 +00 +39 +f7 +7c +03 +c1 +eb +02 +ff +cb +c1 +e3 +10 +09 +c3 +8b +81 +b8 +00 +00 +00 +89 +5c +24 +c0 +44 +8b +91 +9c +00 +00 +00 +41 +39 +c2 +44 +0f +4d +d0 +44 +89 +54 +24 +c8 +4c +8b +51 +50 +8b +a9 +94 +00 +00 +00 +4d +8d +2c +2a +4d +89 +e9 +49 +f7 +dd +49 +83 +e5 +03 +8b +41 +44 +2d +06 +01 +00 +00 +31 +ff +29 +c5 +44 +8b +99 +a0 +00 +00 +00 +0f +4e +ef +4b +8d +34 +1a +45 +0f +b7 +21 +43 +0f +b7 +5c +19 +ff +48 +8b +79 +60 +8b +54 +24 +c0 +66 +42 +3b +5c +06 +ff +0f +84 +9a +00 +00 +00 +41 +21 +d0 +46 +0f +b7 +04 +47 +41 +39 +e8 +0f +86 +6e +01 +00 +00 +81 +ea +00 +00 +01 +00 +0f +88 +62 +01 +00 +00 +66 +42 +3b +5c +06 +ff +74 +75 +41 +21 +d0 +46 +0f +b7 +04 +47 +41 +39 +e8 +0f +86 +49 +01 +00 +00 +81 +ea +00 +00 +01 +00 +0f +88 +3d +01 +00 +00 +66 +42 +3b +5c +06 +ff +74 +50 +41 +21 +d0 +46 +0f +b7 +04 +47 +41 +39 +e8 +0f +86 +24 +01 +00 +00 +81 +ea +00 +00 +01 +00 +0f +88 +18 +01 +00 +00 +66 +42 +3b +5c +06 +ff +75 +91 +eb +29 +41 +21 +d0 +46 +0f +b7 +04 +47 +41 +39 +e8 +0f +86 +fd +00 +00 +00 +81 +ea +00 +00 +01 +00 +0f +88 +f1 +00 +00 +00 +66 +42 +3b +5c +06 +ff +0f +85 +66 +ff +ff +ff +66 +47 +3b +24 +02 +0f +85 +5b +ff +ff +ff +89 +54 +24 +c0 +4b +8d +34 +10 +48 +ba +f8 +fe +ff +ff +ff +ff +ff +ff +4a +8d +b4 +2e +08 +01 +00 +00 +4b +8d +bc +29 +08 +01 +00 +00 +0f +18 +14 +16 +0f +18 +14 +17 +48 +8b +04 +16 +48 +33 +04 +17 +75 +26 +48 +8b +44 +16 +08 +48 +33 +44 +17 +08 +75 +16 +48 +8b +44 +16 +10 +48 +33 +44 +17 +10 +75 +06 +48 +83 +c2 +18 +eb +d8 +48 +83 +c2 +08 +48 +83 +c2 +08 +a9 +ff +ff +00 +00 +75 +1b +a9 +ff +ff +ff +ff +75 +0d +48 +83 +c2 +04 +48 +c1 +e8 +20 +66 +09 +c0 +75 +07 +c1 +e8 +10 +48 +83 +c2 +02 +2c +01 +48 +83 +d2 +00 +48 +8d +04 +17 +4c +29 +c8 +3d +02 +01 +00 +00 +7d +3d +44 +39 +d8 +7f +11 +4b +8d +34 +1a +48 +8b +79 +60 +8b +54 +24 +c0 +e9 +26 +ff +ff +ff +41 +89 +c3 +44 +89 +81 +98 +00 +00 +00 +3b +44 +24 +c8 +7d +24 +49 +8d +34 +02 +41 +0f +b7 +5c +01 +ff +48 +8b +79 +60 +8b +54 +24 +c0 +e9 +ff +fe +ff +ff +41 +bb +02 +01 +00 +00 +44 +89 +81 +98 +00 +00 +00 +8b +81 +9c +00 +00 +00 +41 +39 +c3 +41 +0f +4e +c3 +48 +8b +74 +24 +d8 +48 +8b +7c +24 +d0 +48 +8b +5c +24 +e0 +48 +8b +6c +24 +e8 +4c +8b +64 +24 +f0 +4c +8b +6c +24 +f8 +c2 +00 +00 +0d +0a +61 +73 +6d +36 +38 +36 +20 +77 +69 +74 +68 +20 +6d +61 +73 +6d +2c +20 +6f +70 +74 +69 +6d +69 +73 +65 +64 +20 +61 +73 +73 +65 +6d +62 +6c +79 +20 +63 +6f +64 +65 +20 +66 +72 +6f +6d +20 +42 +72 +69 +61 +6e +20 +52 +61 +69 +74 +65 +72 +2c +20 +77 +72 +69 +74 +74 +65 +6e +20 +31 +39 +39 +38 +2c +20 +63 +6f +6e +76 +65 +72 +74 +65 +64 +20 +74 +6f +20 +61 +6d +64 +20 +36 +34 +20 +62 +79 +20 +47 +69 +6c +6c +65 +73 +20 +56 +6f +6c +6c +61 +6e +74 +20 +32 +30 +30 +35 +0d +0a +00 +c2 +00 +00