-1

I have an array in memory that holds certain hex values that describe assembly instructions. For example:

708877665544332211 = jump 0x1122334455667788

70 indicates a jump in assembly and the following hex numbers are what I need to concatenate. I've already tried doing,

address |= memory[1];
address |= memory[2]<<8;
address |= memory[3]<<16;
address |= memory[4]<<24;
address |= memory[5]<<32;
address |= memory[6]<<40;
address |= memory[7]<<48;
address |= memory[8]<<56;

The string that was outputted was:

0x100: 708877665544332211 | jump 1432778700

Where am I going wrong in the concatenation?

EDIT: Following Benjamin's suggestion, I changed it to:

With print statement printf("APPEND: %016llx", address) to debug, I found that the uint64_t was being changed as:

APPEND: 0000000000002211
APPEND: 0000000000332211
APPEND: 0000000044332211
APPEND: 0000000044332255
APPEND: 0000000044336655
APPEND: 0000000044776655

If the address is a 64bit integer, why does it appear to be behaving as a 32bit integer?

zx485
  • 28,498
  • 28
  • 50
  • 59
SwaggyC
  • 38
  • 9
  • 1
    I'd like to make an observation as to why your code doesn't work as you expected in the first case: Regarding `address |= memory[5]<<32;`, `address |= memory[6]<<40;`, `address |= memory[7]<<48;`, and `address |= memory[8]<<56;` there is the problem of integer promotion. `address |= memory[5]<<32;` for example will promote memory[5] to an int (on your platform a 32-bit value). If you attempt to shift that left 32 bits that exceeds the width of the 32-bit type.This will cause undefined behavior and is the reason you get unusual results place into `address` – Michael Petch Mar 31 '17 at 22:23
  • You can cast using something like `address |= ((unsigned long long)memory[5])<<32` . This casts memory[5] to a 64-bit type and then the shift is performed on that. It is assumed you define `address` as an `unsigned long long` – Michael Petch Mar 31 '17 at 22:25
  • I'm a bit surprised though that the compiler wouldn't have warned you about this issue at compile time. – Michael Petch Mar 31 '17 at 22:29

3 Answers3

1

The problem is the byte order. Maybe you can try the following:

address = memory[8];
address |= memory[7]<<8;
address |= memory[6]<<16;
address |= memory[5]<<24;
address |= memory[4]<<32;
address |= memory[3]<<40;
address |= memory[2]<<48;
address |= memory[1]<<56;

P.S.: It would help if you code post the full code (including the printing).

Benjamin J.
  • 1,239
  • 1
  • 15
  • 28
1

Decimal number 1432778700 in hex is 0x‭556677CC‬. This is most probably a problem with the data type of variable 'address'. It has to be able to hold 8 bytes. So you will have to use a data type like unsigned long long int.

Once you have solved that, then you need to know whether the address is stored in memory in little endian or big endian order and process it accordingly.

Update: Just saw your edited question. If you expect the following conversion: 708877665544332211 into 0x1122334455667788

then even something like this will work:

unsigned char bMemory[] = {0x70,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11};

int main()
{
    unsigned long long int address = *((unsigned long long int *)(&bMemory[1]));
    printf("\n Address is %llX", address );

    return 0;
}
  • This will violate C's [strict aliasing rules](http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) . – Michael Petch Mar 31 '17 at 23:51
  • 1
    @MichaelPetch in one of the comments there is "the `char *` will not break it, as it can be retyped to anything"... (I have no idea what is correct, but I break the strict aliasing rule often when I need to work with the same memory content in different ways :/ ....old habits die hard and if all you see are bits...) – Ped7g Apr 01 '17 at 00:17
  • @Ped7g In this case you are accessing an element of the `bMemory` array (which is an array of characters) through a pointer of `unsigned long long`. This violates strict aliasing. Had you had the reverse like a pointer to `unsigned long long` the exception to the aliasing rules would have allowed you to access each byte of the `unsigned long long` through a `char *`. – Michael Petch Apr 01 '17 at 01:37
  • In this case I'd probably consider using memcpy like this `unsigned long long address;` `memcpy (&address, bMemory+1, sizeof (address));` . If using builtins and optimization this should reduce to reasonable code. – Michael Petch Apr 01 '17 at 02:18
0

I figured out what I was doing wrong. I should have just been appending the bits and then shifting them down 8 every time.

for(int i = 8; i < 0; i--){
  address<<=8;
  address |= memory[i];
}
SwaggyC
  • 38
  • 9
  • `0 < i` ... and that doesn't make sense... and I know what, you have to cast `memory[8]` to 64b first before `<<56`. At least gcc emits warning: *"[x86-64 gcc 6.3] warning: left shift count >= width of type [-Wshift-count-overflow]"* ... are you using `-Wall`? – Ped7g Apr 01 '17 at 00:26