Nick Glencross wrote:

Having never had access to a Tru64 system, does that mean that parrot is compiled 64 bit?

Two initial comments:

* This is a platform that we've not had a chance to test on, so I'm grateful to see it tested on a new platform. It was hoped that it would work, but to stop the test failing it was supposed to skip them until formally tested. Why did the skipping not work though? What would the intsize attribute be (from config_lib.pasm I guess)

* Secondly, any chance I can get access to other platforms, such as this one, to troubleshoot the problem? If not, perhaps I can instrument the code and have the results sent back to me...

Cheers,

Nick

There have been updates have been made to the md5 library and tests; great!

Leo: There's a gremlin in the onload routine related to endianess. Although the endian register is correct, it doesn't now set the global on big endian systems... Might be worth moving the store_global after the is_little_endian label.

I'm also attaching an instrumented version of runtime/parrot/library/Digest/MD5.imc, so if you've got a 64-bit or big endian system, perhaps you could try the following with this updated file:

[EMAIL PROTECTED] parrot $ md5sum ABI_CHANGES
84195669527b120240cdd20a02edd63b  ABI_CHANGES

./parrot  examples/assembly/md5sum.imc  ABI_CHANGES > md5.log

If the last line of this log file doesn't say 8419... then send me details of your platform, and the logfile.

Thanks in advance,

Nick Glencross
# Parrot md5sum; Nick Glencross <[EMAIL PROTECTED]>
#                Improvements from Leo
#
# Based on md5.c, from md5sum
#           written by Ulrich Drepper <[EMAIL PROTECTED]>, 1995.

=head1 NAME

MD5.imc - calculate MD5 checksums

=head1 SYNOPSIS

  load_bytecode "library/Digest/MD5.imc"
  $P0 = _md5sum("foo")
  _md5_print($P0)

=head1 DESCRIPTION

This is a pure Parrot MD5 hash routine. Therefore you should run it
with the JIT core if possible.

=head1 SUBROUTINES

=head2 _md5sum

Pass in a string, returns an Integer array with the result

=head2 _md5_print

Pass it the Integer array to print the checksum.

=head2 _md5_hex

Pass it the Integer array to get the checksum as string.

=head1 BUGS

Only tested so far on i386.

=over 4

=item * Might work on 64 bit platforms

=item * Might not work on big endian systems (confirmed)

=back

=cut

####################################
# export function entries to globals

.sub onload @LOAD
    .local pmc endian
    endian = new Integer
    endian = 0
    
    $P0 = _config()

    $I0 = $P0["intsize"]
    if $I0 == 4 goto is_4byte_word

    printerr "This doesn't seem to be a 32 bit processor: "
    printerr "Please verify the MD5 checksum\n"

is_4byte_word:

    $I0 = $P0["bigendian"]
    unless $I0 goto is_little_endian
    endian = 1
    printerr "This appears to be a big endian processor: "
    printerr "Please verify the MD5 checksum\n"

is_little_endian:

    store_global "Digest", "_md5_swap_endian", endian

    .local pmc f
    f = find_global "Digest", "_md5sum"
    global "_md5sum" = f
    f = find_global "Digest", "_md5_print"
    global "_md5_print" = f
    f = find_global "Digest", "_md5_hex"
    global "_md5_hex" = f
.end

.include "library/config.imc"

###########################################################################
# Main entry point

.namespace ["Digest"]

.sub _md5sum
    .param string str

    .local pmc buffer, context
    buffer = new FixedIntegerArray

    context = new FixedIntegerArray
    context = 4

    $P0 = find_global "Digest", "_md5_swap_endian"
    $I0 = $P0
    _md5_create_buffer (str, buffer, $I0)

    # _print_buffer (buffer, 8)

    _md5_init (context)
    _md5_process_buffer (context, buffer)

    .return(context)

.end


###########################################################################
# Low-level macros used in MD5

# A parrot rol instruction might be good (as it can often be JIT'd)
.macro rol (x,n,  out)
    .out = .x << .n
    $I1000 = 32 - .n
    $I1000 = .x >>> $I1000
    $I1000 = $I1000 & 0xffffffff
    .out |= $I1000
.endm

.macro FF (b,c,d)
    tmp = .c ~ .d
    tmp = .b & tmp
    tmp = .d ~ tmp
.endm

.macro FH (b,c,d)
    tmp = .b ~ .c
    tmp = tmp ~ .d
.endm

.macro FI (b,c,d)
    tmp = ~.d
    tmp = .b | tmp
    tmp = .c ~ tmp
.endm

###########################################################################
# Higher level MD5 operations

.macro common (a, b, k, s, T)
    .a += tmp
    .a += .T
    $I99 = .k + idx
    tmp = buffer[$I99]
    .a += tmp
    .rol (.a, .s, tmp)
    .a = .b + tmp
.endm

.macro OP1 (aa,bb,cc,dd, kk, ss, TT)
    .FF (.bb,.cc,.dd)
    .common (.aa, .bb, .kk, .ss, .TT)
.endm

.macro OP2 (aa,bb,cc,dd, kk, ss, TT)
    .FF (.dd,.bb,.cc)
    .common (.aa, .bb, .kk, .ss, .TT)
.endm

.macro OP3 (aa,bb,cc,dd, kk, ss, TT)
    .FH (.bb,.cc,.dd)
    .common (.aa, .bb, .kk, .ss, .TT)
.endm

.macro OP4 (aa,bb,cc,dd, kk, ss, TT)
    .FI (.bb,.cc,.dd)
    .common (.aa, .bb, .kk, .ss, .TT)
.endm

###########################################################################

# Swap the bytes which make up a word

.macro swap (w)

     print "Before swap: "
     $S0 = _number_as_hex (.w, 8)
     print $S0
     print "\n"

     $I10 = .w & 0x000000ff
     $I11 = .w & 0x0000ff00
     $I12 = .w & 0x00ff0000
     $I13 = .w & 0xff000000

     $I10 = $I10 <<  24
     $I11 = $I11 <<  8
     $I12 = $I12 >>> 8
     $I13 = $I13 >>> 24

     $I10 = $I10 | $I11
     $I10 = $I10 | $I12
     .w   = $I10 | $I13

     # For 64-bit architectures
     .w   = .w & 0xffffffff

     print "After  swap: "
     $S0 = _number_as_hex (.w, 8)
     print $S0
     print "\n"

.endm

###########################################################################

# Set the initial MD5 constants

.sub _md5_init
    .param pmc context

    # Initial MD5 constants
    context[0] = 0x67452301
    context[1] = 0xefcdab89
    context[2] = 0x98badcfe
    context[3] = 0x10325476

.end

###########################################################################

# Create a buffer from the requested buffer

.sub _md5_create_buffer
    .param string str
    .param pmc  buffer
    .param int endian

    .local int counter
    .local int subcounter
    .local int slow_counter

    .local int word, len

     len = length str

     $I1 = len - 1

     # Work out how many words to allocate
     .local int words
     words = len + 8
     words = words | 63
     words = words + 1
     words = words / 4

     buffer = words

     word         = 0
     counter      = 0
     subcounter   = 0
     slow_counter = 0

md5_create_buffer_loop:

     $I5 = counter + subcounter

     if $I5 > len goto md5_create_buffer_break

     # MD5 pad character, which goes last
     $I4 = 0x80

     if $I5 > $I1 goto string_char
     $I4 = ord str, $I5

string_char:

     word = word << 8
     word = word | $I4

     inc subcounter
     if subcounter != 4 goto md5_create_buffer_loop
     if endian goto endian_ok
         .swap (word)
endian_ok:


     buffer[slow_counter] = word

     word         = 0
     counter      = counter + 4
     subcounter   = 0
     inc slow_counter

     goto md5_create_buffer_loop

md5_create_buffer_break:

     # Check for a partial word

     if subcounter == 0 goto complete
     subcounter = 4 - subcounter
     .local int shift
     shift = 8*subcounter
     word = word << shift
     if endian goto endian_ok2
     .swap (word)
endian_ok2:

     buffer[slow_counter] = word

complete:

     # The number of bits in the string go into the last two words

     $I1 = len >>> 29
     words = words - 1
     buffer[words] = $I1

     $I0 = len << 3
     words = words - 1
     buffer[words] = $I0

.end

###########################################################################

.sub _md5_process_buffer
    .param pmc    context
    .param pmc  buffer

    .local int A, B, C, D
    .local int A_save, B_save, C_save, D_save

    .local int tmp, idx, len

    idx = 0
    len = elements buffer

    A = context[0]
    B = context[1]
    C = context[2]
    D = context[3]

md5_loop:

    A_save = A
    B_save = B
    C_save = C
    D_save = D

    $S0 = _format_vals (A,B,C,D)
    print $S0
    print "\n"

    # Round 1.
    .OP1 (A, B, C, D, 0,  7, 0xd76aa478)

    $S0 = _format_vals (A,B,C,D)
    print $S0
    print "\n"

    .OP1 (D, A, B, C, 1, 12, 0xe8c7b756)
    .OP1 (C, D, A, B, 2, 17, 0x242070db)
    .OP1 (B, C, D, A, 3, 22, 0xc1bdceee)
    .OP1 (A, B, C, D, 4,  7, 0xf57c0faf)
    .OP1 (D, A, B, C, 5, 12, 0x4787c62a)
    .OP1 (C, D, A, B, 6, 17, 0xa8304613)
    .OP1 (B, C, D, A, 7, 22, 0xfd469501)
    .OP1 (A, B, C, D, 8,  7, 0x698098d8)
    .OP1 (D, A, B, C, 9, 12, 0x8b44f7af)
    .OP1 (C, D, A, B, 10,17, 0xffff5bb1)
    .OP1 (B, C, D, A, 11,22, 0x895cd7be)
    .OP1 (A, B, C, D, 12, 7, 0x6b901122)
    .OP1 (D, A, B, C, 13,12, 0xfd987193)
    .OP1 (C, D, A, B, 14,17, 0xa679438e)
    .OP1 (B, C, D, A, 15,22, 0x49b40821)

    # Round 2.
    .OP2 (A, B, C, D,  1,  5, 0xf61e2562)
    .OP2 (D, A, B, C,  6,  9, 0xc040b340)
    .OP2 (C, D, A, B, 11, 14, 0x265e5a51)
    .OP2 (B, C, D, A,  0, 20, 0xe9b6c7aa)
    .OP2 (A, B, C, D,  5,  5, 0xd62f105d)
    .OP2 (D, A, B, C, 10,  9, 0x02441453)
    .OP2 (C, D, A, B, 15, 14, 0xd8a1e681)
    .OP2 (B, C, D, A,  4, 20, 0xe7d3fbc8)
    .OP2 (A, B, C, D,  9,  5, 0x21e1cde6)
    .OP2 (D, A, B, C, 14,  9, 0xc33707d6)
    .OP2 (C, D, A, B,  3, 14, 0xf4d50d87)
    .OP2 (B, C, D, A,  8, 20, 0x455a14ed)
    .OP2 (A, B, C, D, 13,  5, 0xa9e3e905)
    .OP2 (D, A, B, C,  2,  9, 0xfcefa3f8)
    .OP2 (C, D, A, B,  7, 14, 0x676f02d9)
    .OP2 (B, C, D, A, 12, 20, 0x8d2a4c8a)

    # Round 3.
    .OP3 (A, B, C, D,  5,  4, 0xfffa3942)
    .OP3 (D, A, B, C,  8, 11, 0x8771f681)
    .OP3 (C, D, A, B, 11, 16, 0x6d9d6122)
    .OP3 (B, C, D, A, 14, 23, 0xfde5380c)
    .OP3 (A, B, C, D,  1,  4, 0xa4beea44)
    .OP3 (D, A, B, C,  4, 11, 0x4bdecfa9)
    .OP3 (C, D, A, B,  7, 16, 0xf6bb4b60)
    .OP3 (B, C, D, A, 10, 23, 0xbebfbc70)
    .OP3 (A, B, C, D, 13,  4, 0x289b7ec6)
    .OP3 (D, A, B, C,  0, 11, 0xeaa127fa)
    .OP3 (C, D, A, B,  3, 16, 0xd4ef3085)
    .OP3 (B, C, D, A,  6, 23, 0x04881d05)
    .OP3 (A, B, C, D,  9,  4, 0xd9d4d039)
    .OP3 (D, A, B, C, 12, 11, 0xe6db99e5)
    .OP3 (C, D, A, B, 15, 16, 0x1fa27cf8)
    .OP3 (B, C, D, A,  2, 23, 0xc4ac5665)

    # Round 4.
    .OP4 (A, B, C, D,  0,  6, 0xf4292244)
    .OP4 (D, A, B, C,  7, 10, 0x432aff97)
    .OP4 (C, D, A, B, 14, 15, 0xab9423a7)
    .OP4 (B, C, D, A,  5, 21, 0xfc93a039)
    .OP4 (A, B, C, D, 12,  6, 0x655b59c3)
    .OP4 (D, A, B, C,  3, 10, 0x8f0ccc92)
    .OP4 (C, D, A, B, 10, 15, 0xffeff47d)
    .OP4 (B, C, D, A,  1, 21, 0x85845dd1)
    .OP4 (A, B, C, D,  8,  6, 0x6fa87e4f)
    .OP4 (D, A, B, C, 15, 10, 0xfe2ce6e0)
    .OP4 (C, D, A, B,  6, 15, 0xa3014314)
    .OP4 (B, C, D, A, 13, 21, 0x4e0811a1)
    .OP4 (A, B, C, D,  4,  6, 0xf7537e82)
    .OP4 (D, A, B, C, 11, 10, 0xbd3af235)
    .OP4 (C, D, A, B,  2, 15, 0x2ad7d2bb)
    .OP4 (B, C, D, A,  9, 21, 0xeb86d391)

    A += A_save
    B += B_save
    C += C_save
    D += D_save

    idx += 16

    $S0 = _format_vals (A,B,C,D)
    print $S0
    print "\n"

    if idx < len goto md5_loop

    context[0] = A
    context[1] = B
    context[2] = C
    context[3] = D

.end

###########################################################################

# format four hex values

.sub _format_vals
    .param int A
    .param int B
    .param int C
    .param int D

    $P0 = new FixedIntegerArray
    $P0 = 4
    $P0[0] = A
    $P0[1] = B
    $P0[2] = C
    $P0[3] = D

    sprintf $S0, "%08lx%08lx%08lx%08lx", $P0
    .return($S0)
.end

###########################################################################

# Print the final checksum

.sub _md5_print
    .param pmc context

    .local int A
    .local int B
    .local int C
    .local int D

    A = context[0]
    B = context[1]
    C = context[2]
    D = context[3]

    $P0 = find_global "Digest", "_md5_swap_endian"
    if $P0 goto dont_swap

    .swap (A)
    .swap (B)
    .swap (C)
    .swap (D)

dont_swap:

    $S0 = _format_vals (A,B,C,D)
    print $S0
.end

.sub _md5_hex
    .param pmc context

    .local int A
    .local int B
    .local int C
    .local int D

    A = context[0]
    B = context[1]
    C = context[2]
    D = context[3]

    $P0 = find_global "Digest", "_md5_swap_endian"
    if $P0 goto dont_swap

    .swap (A)
    .swap (B)
    .swap (C)
    .swap (D)

dont_swap:

    $S0 = _format_vals (A,B,C,D)
    .return($S0)
.end

###########################################################################

# For debugging

.sub _print_buffer
    .param pmc buffer
    .param int word_size

    .local int size

    size = buffer

    .local int counter
    .local int value

    counter = 0

print_buffer_loop:
    if counter >= size goto print_buffer_done
    value = buffer[counter]
    $S0 = _number_as_hex (value, word_size)
    print $S0
    print " | "
    counter = counter + 1
    goto print_buffer_loop

print_buffer_done:

    print "\n"

.end

###########################################################################

# Also for debugging

.sub _number_as_hex
    .param int number
    .param int word_size

    $P0 = new FixedIntegerArray
    $P0 = 1
    $P0[0] = number

    $S1 = "%0"
    $S0 = word_size
    concat $S1, $S0
    concat $S1, "lx"

    sprintf $S0, $S1, $P0

    .return($S0)

.end

Reply via email to