[colug-432] Jamming Bytes Into A uint64_t

jep200404 at columbus.rr.com jep200404 at columbus.rr.com
Fri Feb 2 20:19:10 EST 2018


Here is some code to show some ways of jamming bytes into a uint64_t.

struct fait_accompli_struct deliberately has voids.
Notice how the data in the voids in the structure varies from run to run.

1.c does not overwrite the uint64_t buf.b. 1.c is the control.
2.c uses casting to access individual bytes of a uint64_t.
3.c uses a union to access individual bytes of a uint64_t.

2.c and 3.c are susceptible to byte order portability problems.
For that reason I am wary of using these techniques without knowing
more about the end use.

4.c always does things in host order.
Sometimes that is what you want. Sometimes it is not.
UINT64_AS_BYTES(i, x, y) is a very ugly macro.
UINT64_AS_BYTES(0, x, y) is always of the least significant byte
regardless of the machine's byte order.
and UINT64_AS_BYTES(7, x, y) is always of the most significant byte
regardless of the machine's byte order.

I highly recommend:

    Advanced Programming in the UNIX Environment
    W. Richard Stevens
    Stephen A. Rago

W. Richard Stevens was an extraordinarly superb writer.

There is a third edition. I only have the first two editions.
In the second edition study, 16.3.1 Byte Ordering starting on p549.

Study:

    man htonl

    https://gnunet.org/book/export/html/363

-------------------------------------------------------------------------------

doj at sbc:~/byte-jammer$ head -v -n 1000 *.h *c
==> fait_accompli.h <==
/* Imagine that you can not change this header file
*  (to put a union in for b). */

struct fait_accompli_struct {
    /* ints were chosen to deliberately mess up the alignment.
    *  Study the output to see the voids in the structure.
    *  sizeof() can be deceptive. */

    int a;
    uint64_t b;
    int c;
};


==> 1.c <==
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include "fait_accompli.h"

int main(int argc, char *argv[])
{
    struct fait_accompli_struct buf;
    int i;

    buf.a = 0x11223344;
    buf.c = 0x55667788;
    buf.b = 0x0123456789ABCDEFUL;

    i = write(STDOUT_FILENO, &buf, sizeof(buf));
    fprintf(
        stderr,
        "i=%d sizeof(int)=%ld sizeof(uint64_t)=%ld sizeof(buf)=%ld\n",
        i, sizeof(int), sizeof(uint64_t), sizeof(buf)
    );

    exit(EXIT_SUCCESS);
}


==> 2.c <==
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include "fait_accompli.h"

#define UINT64_AS_BYTES(x) ((unsigned char *)&(x))

int main(int argc, char *argv[])
{
    struct fait_accompli_struct buf;
    int i;

    buf.a = 0x11223344;
    buf.c = 0x55667788;
    buf.b = 0x0123456789ABCDEFUL;
    for (i = 0; i < 4; i++)
        UINT64_AS_BYTES(buf.b)[i+2] = 'A' + i;

    i = write(STDOUT_FILENO, &buf, sizeof(buf));
    fprintf(
        stderr,
        "i=%d sizeof(int)=%ld sizeof(uint64_t)=%ld sizeof(buf)=%ld\n",
        i, sizeof(int), sizeof(uint64_t), sizeof(buf)
    );

    exit(EXIT_SUCCESS);
}


==> 3.c <==
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include "fait_accompli.h"

union uint64_bytes_union {
    uint64_t i;
    unsigned char b[sizeof(uint64_t)];
};

int main(int argc, char *argv[])
{
    struct fait_accompli_struct buf;
    int i;

    buf.a = 0x11223344;
    buf.c = 0x55667788;
    buf.b = 0x0123456789ABCDEFUL;
    for (i = 0; i < 4; i++) {
        union uint64_bytes_union *p = (void *)&buf.b;

        p->b[i+2] = 'A' + i;
    }

    i = write(STDOUT_FILENO, &buf, sizeof(buf));
    fprintf(
        stderr,
        "i=%d sizeof(int)=%ld sizeof(uint64_t)=%ld sizeof(buf)=%ld\n",
        i, sizeof(int), sizeof(uint64_t), sizeof(buf)
    );

    exit(EXIT_SUCCESS);
}


==> 4.c <==
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include "fait_accompli.h"

#define MASK(width, offset) (((1UL<<(width)) - 1) << (offset))

#define UINT64_AS_BYTES(i, x, y) (\
    ((x) & ~MASK(8, 8*(i))) |\
    ((y) << (8*(i)))\
)

int main(int argc, char *argv[])
{
    struct fait_accompli_struct buf;
    int i;

    buf.a = 0x11223344;
    buf.c = 0x55667788;
    buf.b = 0x0123456789ABCDEFUL;
    for (i = 0; i < 4; i++)
        buf.b = UINT64_AS_BYTES(
            i+2, buf.b, (unsigned long)('A' + i)
        );

    i = write(STDOUT_FILENO, &buf, sizeof(buf));
    fprintf(
        stderr,
        "i=%d sizeof(int)=%ld sizeof(uint64_t)=%ld sizeof(buf)=%ld\n",
        i, sizeof(int), sizeof(uint64_t), sizeof(buf)
    );

    exit(EXIT_SUCCESS);
}

doj at sbc:~/byte-jammer$

The following were run on a 64-bit little-endian PC running 64-bit Ubuntu.

doj at sbc:~/byte-jammer$ ./1 | xxd -g 1 -u
i=24 sizeof(int)=4 sizeof(uint64_t)=8 sizeof(buf)=24
00000000: 44 33 22 11 00 00 00 00 EF CD AB 89 67 45 23 01  D3".........gE#.
00000010: 88 77 66 55 FF 7F 00 00                          .wfU....
doj at sbc:~/byte-jammer$ ./2 | xxd -g 1 -u
i=24 sizeof(int)=4 sizeof(uint64_t)=8 sizeof(buf)=24
00000000: 44 33 22 11 00 00 00 00 EF CD 41 42 43 44 23 01  D3".......ABCD#.
00000010: 88 77 66 55 FE 7F 00 00                          .wfU....
doj at sbc:~/byte-jammer$ ./3 | xxd -g 1 -u
i=24 sizeof(int)=4 sizeof(uint64_t)=8 sizeof(buf)=24
00000000: 44 33 22 11 00 00 00 00 EF CD 41 42 43 44 23 01  D3".......ABCD#.
00000010: 88 77 66 55 FF 7F 00 00                          .wfU....
doj at sbc:~/byte-jammer$ ./4 | xxd -g 1 -u
i=24 sizeof(int)=4 sizeof(uint64_t)=8 sizeof(buf)=24
00000000: 44 33 22 11 00 00 00 00 EF CD 41 42 43 44 23 01  D3".......ABCD#.
00000010: 88 77 66 55 FE 7F 00 00                          .wfU....
doj at sbc:~/byte-jammer$

Notice how the data in the structure voids can change from run to run.

doj at sbc:~/byte-jammer$ ./4 | xxd -g 1 -u
i=24 sizeof(int)=4 sizeof(uint64_t)=8 sizeof(buf)=24
00000000: 44 33 22 11 00 00 00 00 EF CD 41 42 43 44 23 01  D3".......ABCD#.
00000010: 88 77 66 55 FC 7F 00 00                          .wfU....
doj at sbc:~/byte-jammer$ ./4 | xxd -g 1 -u
i=24 sizeof(int)=4 sizeof(uint64_t)=8 sizeof(buf)=24
00000000: 44 33 22 11 00 00 00 00 EF CD 41 42 43 44 23 01  D3".......ABCD#.
00000010: 88 77 66 55 FD 7F 00 00                          .wfU....
doj at sbc:~/byte-jammer$ ./4 | xxd -g 1 -u
i=24 sizeof(int)=4 sizeof(uint64_t)=8 sizeof(buf)=24
00000000: 44 33 22 11 00 00 00 00 EF CD 41 42 43 44 23 01  D3".......ABCD#.
00000010: 88 77 66 55 FD 7F 00 00                          .wfU....
doj at sbc:~/byte-jammer$

Hopefully someone will post the output of the following commands
run on a 64-bit big-endian computer.

    ./1 | xxd -g 1 -u
    ./2 | xxd -g 1 -u
    ./3 | xxd -g 1 -u
    ./4 | xxd -g 1 -u



More information about the colug-432 mailing list