1

I'm writing a function that would compute CRC *value for a string. ( * arbitrary width of 8-64 ). The function accepts 9 parameters, but to illustrate the problem with left-bitshifting, I'm posting only a snippet.

void leftshift(unsigned char* str, unsigned int n, int nshiftleft, unsigned __int64 *value)
{
  unsigned __int64 x = str[0];
  x = x << nshiftleft;
  *value = x;
}

If str[0] is "A" (65) and nshiftleft is 56, I expect value to be 0x4100000000000000 (65 << 56), but it is 0x0000000000000041. The snippet produces a correct result only if I use a literal value, like follows:

void leftshift(unsigned char* str, unsigned int n, int nshiftleft, unsigned __int64 *value)
{
  unsigned __int64 x = str[0];
  x = x << 56;
  *value = x;
}

How to achieve this? Please help.

Edit: I'm a Windows user and I intend to use this function from the scripting language AutoHotkey.

The following code works fine: CRC-64/ECMA_182 value for the string "AutoHotkey" = 0x36990A8E358262B4

void crc64(unsigned __int64 r, unsigned char* s, int n, unsigned __int64 *value)
{
 unsigned __int64 poly = 0x42F0E1EBA9EA3693;
 unsigned __int64 t    = 0x8000000000000000;
 unsigned __int64 x    = 0;

  for (int i=0; i<n; i+=1)
  {
     x = (__int64)s[i];
     r ^= x << 56;
     r = (r & t) ? ( (r << 1) ^ poly ) : (r << 1);
     r = (r & t) ? ( (r << 1) ^ poly ) : (r << 1);
     r = (r & t) ? ( (r << 1) ^ poly ) : (r << 1);
     r = (r & t) ? ( (r << 1) ^ poly ) : (r << 1);
     r = (r & t) ? ( (r << 1) ^ poly ) : (r << 1);
     r = (r & t) ? ( (r << 1) ^ poly ) : (r << 1);
     r = (r & t) ? ( (r << 1) ^ poly ) : (r << 1);
     r = (r & t) ? ( (r << 1) ^ poly ) : (r << 1);
   }

  *value = r;
}

The above is the full code. I compile it with LCC x64 (windows) to .obj (without any errors/warning) and extract the .text section which is as follows:

5589e583ec1c535657c745f89336eaa9c745fcebe1f042c745f000000000c745f400000080c745e800000000c745ec00000000c745e400000000e92c0200008b45108b55e40fb6041089c0998945e88955ec8b45e88b55ec89c2b800000000c1e21831450831550c8b45088b550c2345f02355f483fa00750583f80074148b45088b550c0fa4c201d1e03345f83355fceb108b75088b7d0c89f089fa0fa4c201d1e089450889550c8b45088b550c2345f02355f483fa00750583f80074148b45088b550c0fa4c201d1e03345f83355fceb108b75088b7d0c89f089fa0fa4c201d1e089450889550c8b45088b550c2345f02355f483fa00750583f80074148b45088b550c0fa4c201d1e03345f83355fceb108b75088b7d0c89f089fa0fa4c201d1e089450889550c8b45088b550c2345f02355f483fa00750583f80074148b45088b550c0fa4c201d1e03345f83355fceb108b75088b7d0c89f089fa0fa4c201d1e089450889550c8b45088b550c2345f02355f483fa00750583f80074148b45088b550c0fa4c201d1e03345f83355fceb108b75088b7d0c89f089fa0fa4c201d1e089450889550c8b45088b550c2345f02355f483fa00750583f80074148b45088b550c0fa4c201d1e03345f83355fceb108b75088b7d0c89f089fa0fa4c201d1e089450889550c8b45088b550c2345f02355f483fa00750583f80074148b45088b550c0fa4c201d1e03345f83355fceb108b75088b7d0c89f089fa0fa4c201d1e089450889550c8b45088b550c2345f02355f483fa00750583f80074148b45088b550c0fa4c201d1e03345f83355fceb108b75088b7d0c89f089fa0fa4c201d1e089450889550cff45e48b45e43b45140f8cc8fdffff8b45188b4d088b5d0c89088958045f5e5b89ec5dc3

I am able to call the above machine code with AutoHotkey with proper results. Now, I'm trying to make the above function dynamic, so that it will handle crc-8 to crc-64 in one single function.

I have a working prototype written in AutoHotkey here: https://www.autohotkey.com/boards/viewtopic.php?t=89364 (please scroll down to see the function)

Loop iteration is excruciatingly slow with an interpreted language and hence resorting to c machine code.

Thanks to all for confirming the snippet is correct. I will have to inspect the .obj dump, but have no knowledge in asm. I conclude that the code isn't portable for my need.

SKAN
  • 66
  • 4
  • 2
    [Works fine here](https://godbolt.org/z/P9M1Tze7W) – Nate Eldredge Apr 22 '21 at 05:35
  • 4
    There's no reason why `<< int var` and `<< int literal` should produce different results unless your compiler is very ill. Please provide a [mre] that shows how you are calling this (and printing the results). –  Apr 22 '21 at 05:36
  • 1
    Explain how you're deducing that result, because that shift should deliver exactly what you're asking for, provided you know how to look at it afterward. Taking liberty to remove the worthless `n` argument and actually use the `nshiftleft` argument as intended, [I cannot reproduce your problem](https://ideone.com/cOmOYZ) – WhozCraig Apr 22 '21 at 05:36
  • 1
    What compiler are you using? – user3386109 Apr 22 '21 at 05:37
  • 1
    Make sure that `nshiftleft` has the right value (i.e `56`). – Kfir Ventura Apr 22 '21 at 05:37
  • 3
    I suspect this problem is related to [endianness](https://en.wikipedia.org/wiki/Endianness). Bear in mind that 0x4100000000000000 will be stored with the smallest byte first, making it equivalent to the char array { 0, 0, 0, 0, 0, 0, 0, 0x41 } – r3mainer Apr 22 '21 at 05:37
  • Thanks to all for confirming that the snippet is correct. @WhozCraig: Sorry about n argument. I was trying to show that I was actually doing it in a loop. I have edited my post with proper explanation. – SKAN Apr 22 '21 at 06:47
  • 1
    Use `uint64_t` instead of proprietary types – M.M Apr 22 '21 at 11:11
  • Will do. Thanks @M.M – SKAN Apr 22 '21 at 11:48

2 Answers2

0

The following works fine in x86 and x64 when compiled with Pelles C. I changed the parameter type to unsigned __int64 nshiftleft

void leftshift(unsigned char* str, unsigned int n, unsigned __int64 nshiftleft, unsigned __int64 *value)
{
  unsigned __int64 x = str[0];
  x = x << nshiftleft;
  *value = x;
}

The above works in LCC-win x64 but not in x86.

@r3mainer

I think the problem is that the machine code I'm extracting doesn't have the following line.

x = x << nshiftleft;

The value of 0x0000000000000041 is from the line preceding it.

I'm sure the linker will fix this if I create a windows DLL. But that is not an option as I have to create two DLLs separately for x86 and x64. With the machine code method, I can simply include/call them inside my function embedded as base64/hex text.

Thanks to all.

SKAN
  • 66
  • 4
0

yo cannot create a 64bit integer by shifting a char. You need to create a 64bit number and initialize it with the char converted to 64 bit and then you can shift it. You cannot shift a number of bits larger than the type size.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31