// File: wangyu-[P]pwdgen/lib/md5.cpp
// Function: md5_finish(md5_context*, unsigned char*)
void md5_finish( md5_context *ctx, unsigned char output[16] )
{
    uint32_t last, padn;
    uint32_t high, low;
    unsigned char msglen[8];

    high = ( ctx->total[0] >> 29 )
         | ( ctx->total[1] <<  3 );
    low  = ( ctx->total[0] <<  3 );

    PUT_UINT32_LE( low,  msglen, 0 );
    PUT_UINT32_LE( high, msglen, 4 );

    last = ctx->total[0] & 0x3F;
    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );

    md5_update( ctx, md5_padding, padn );
    md5_update( ctx, msglen, 8 );

    PUT_UINT32_LE( ctx->state[0], output,  0 );
    PUT_UINT32_LE( ctx->state[1], output,  4 );
    PUT_UINT32_LE( ctx->state[2], output,  8 );
    PUT_UINT32_LE( ctx->state[3], output, 12 );
}

// Assembly:
subq $0x38, %rsp
movq %rdi, 0x30(%rsp)
movq %rsi, 0x28(%rsp)
movq 0x30(%rsp), %rax
movl (%rax), %eax
shrl $0x1d, %eax
movq 0x30(%rsp), %rcx
movl 0x4(%rcx), %ecx
shll $0x3, %ecx
orl %ecx, %eax
movl %eax, 0x1c(%rsp)
movq 0x30(%rsp), %rax
movl (%rax), %eax
shll $0x3, %eax
movl %eax, 0x18(%rsp)
movl 0x18(%rsp), %eax
andl $0xff, %eax
movb %al, 0x10(%rsp)
movl 0x18(%rsp), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x11(%rsp)
movl 0x18(%rsp), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, 0x12(%rsp)
movl 0x18(%rsp), %eax
shrl $0x18, %eax
andl $0xff, %eax
movb %al, 0x13(%rsp)
movl 0x1c(%rsp), %eax
andl $0xff, %eax
movb %al, 0x14(%rsp)
movl 0x1c(%rsp), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, 0x15(%rsp)
movl 0x1c(%rsp), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, 0x16(%rsp)
movl 0x1c(%rsp), %eax
shrl $0x18, %eax
andl $0xff, %eax
movb %al, 0x17(%rsp)
movq 0x30(%rsp), %rax
movl (%rax), %eax
andl $0x3f, %eax
movl %eax, 0x24(%rsp)
cmpl $0x38, 0x24(%rsp)
jae 0x403ea5
movl $0x38, %eax
subl 0x24(%rsp), %eax
movl %eax, 0xc(%rsp)
jmp 0x403eb2
movl $0x78, %eax
subl 0x24(%rsp), %eax
movl %eax, 0xc(%rsp)
movl 0xc(%rsp), %eax
movl %eax, 0x20(%rsp)
movq 0x30(%rsp), %rdi
movl 0x20(%rsp), %eax
movl %eax, %edx
leaq 0xd76a4(%rip), %rsi     # 0x4db570
callq 0x403c80
movq 0x30(%rsp), %rdi
leaq 0x10(%rsp), %rsi
movl $0x8, %edx
callq 0x403c80
movq 0x30(%rsp), %rax
movl 0x8(%rax), %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, (%rax)
movq 0x30(%rsp), %rax
movl 0x8(%rax), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x1(%rax)
movq 0x30(%rsp), %rax
movl 0x8(%rax), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x2(%rax)
movq 0x30(%rsp), %rax
movl 0x8(%rax), %eax
shrl $0x18, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x3(%rax)
movq 0x30(%rsp), %rax
movl 0xc(%rax), %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x4(%rax)
movq 0x30(%rsp), %rax
movl 0xc(%rax), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x5(%rax)
movq 0x30(%rsp), %rax
movl 0xc(%rax), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x6(%rax)
movq 0x30(%rsp), %rax
movl 0xc(%rax), %eax
shrl $0x18, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x7(%rax)
movq 0x30(%rsp), %rax
movl 0x10(%rax), %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x8(%rax)
movq 0x30(%rsp), %rax
movl 0x10(%rax), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x9(%rax)
movq 0x30(%rsp), %rax
movl 0x10(%rax), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0xa(%rax)
movq 0x30(%rsp), %rax
movl 0x10(%rax), %eax
shrl $0x18, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0xb(%rax)
movq 0x30(%rsp), %rax
movl 0x14(%rax), %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0xc(%rax)
movq 0x30(%rsp), %rax
movl 0x14(%rax), %eax
shrl $0x8, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0xd(%rax)
movq 0x30(%rsp), %rax
movl 0x14(%rax), %eax
shrl $0x10, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0xe(%rax)
movq 0x30(%rsp), %rax
movl 0x14(%rax), %eax
shrl $0x18, %eax
andl $0xff, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0xf(%rax)
addq $0x38, %rsp
retq
nopl (%rax)