/* * Check for alignment requirements and endianness. * * Called from a shell script check_align.sh to execute one test at a time. * Prohibited unaligned accesses usually cause a SIGBUS. */ #include #include #include #include #include char temp_buffer[256]; static char *get_aligned(int align_by, int offset) { char *p = temp_buffer; intptr_t t; for (;;) { t = (intptr_t) p; if (t % align_by == 0) { return p + offset; } p++; } } static void sigbus_handler(int signum) { (void) signum; printf("SIGBUS\n"); exit(1); } int main(int argc, char *argv[]) { struct sigaction sa; int offset; memset((void *) &sa, 0, sizeof(sa)); sa.sa_handler = sigbus_handler; sigaction(SIGBUS, &sa, NULL); if (argc != 3) { goto usage; } offset = atoi(argv[2]); if (strcmp(argv[1], "uint16_t") == 0) { volatile uint16_t *p_u16; volatile uint8_t *p_u8; p_u16 = (uint16_t *) get_aligned(2, offset); printf("uint16_t offset %d, ptr %p\n", offset, (void *) p_u16); *p_u16 = 0x1122UL; p_u8 = (volatile uint8_t *) p_u16; printf("%02x %02x = 0x%lx\n", (unsigned int) p_u8[0], (unsigned int) p_u8[1], (unsigned long) *p_u16); if (p_u8[0] == 0x11 && p_u8[1] == 0x22) { printf("big endian\n"); } else if (p_u8[0] == 0x22 && p_u8[1] == 0x11) { printf("little endian\n"); } else { printf("unknown endian\n"); } } else if (strcmp(argv[1], "uint32_t") == 0) { volatile uint32_t *p_u32; volatile uint8_t *p_u8; p_u32 = (uint32_t *) get_aligned(4, offset); printf("uint32_t offset %d, ptr %p\n", offset, (void *) p_u32); *p_u32 = 0x11223344UL; p_u8 = (volatile uint8_t *) p_u32; printf("%02x %02x %02x %02x = 0x%lx\n", (unsigned int) p_u8[0], (unsigned int) p_u8[1], (unsigned int) p_u8[2], (unsigned int) p_u8[3], (unsigned long) *p_u32); if (p_u8[0] == 0x11 && p_u8[1] == 0x22 && p_u8[2] == 0x33 && p_u8[3] == 0x44) { printf("big endian\n"); } else if (p_u8[0] == 0x44 && p_u8[1] == 0x33 && p_u8[2] == 0x22 && p_u8[3] == 0x11) { printf("little endian\n"); } else { printf("unknown endian\n"); } } else if (strcmp(argv[1], "uint64_t") == 0) { volatile uint64_t *p_u64; volatile uint8_t *p_u8; p_u64 = (uint64_t *) get_aligned(8, offset); printf("uint64_t offset %d, ptr %p\n", offset, (void *) p_u64); *p_u64 = 0x1122334455667788ULL; p_u8 = (volatile uint8_t *) p_u64; printf("%02x %02x %02x %02x %02x %02x %02x %02x = 0x%llx\n", (unsigned int) p_u8[0], (unsigned int) p_u8[1], (unsigned int) p_u8[2], (unsigned int) p_u8[3], (unsigned int) p_u8[4], (unsigned int) p_u8[5], (unsigned int) p_u8[6], (unsigned int) p_u8[7], (unsigned long long) *p_u64); if (p_u8[0] == 0x11 && p_u8[1] == 0x22 && p_u8[2] == 0x33 && p_u8[3] == 0x44 && p_u8[4] == 0x55 && p_u8[5] == 0x66 && p_u8[6] == 0x77 && p_u8[7] == 0x88) { printf("big endian\n"); } else if (p_u8[0] == 0x88 && p_u8[1] == 0x77 && p_u8[2] == 0x66 && p_u8[3] == 0x55 && p_u8[4] == 0x44 && p_u8[5] == 0x33 && p_u8[6] == 0x22 && p_u8[7] == 0x11) { printf("little endian\n"); } else if (p_u8[0] == 0x44 && p_u8[1] == 0x33 && p_u8[2] == 0x22 && p_u8[3] == 0x11 && p_u8[4] == 0x88 && p_u8[5] == 0x77 && p_u8[6] == 0x66 && p_u8[7] == 0x55) { printf("mixed endian\n"); } else { printf("unknown endian\n"); } } else if (strcmp(argv[1], "double") == 0) { volatile double *p_dbl; volatile uint8_t *p_u8; p_dbl = (double *) get_aligned(8, offset); printf("double offset %d, ptr %p\n", offset, (void *) p_dbl); *p_dbl = 112233445566778899.0; /* >>> struct.pack('>d', 112233445566778899).encode('hex') * '4378ebbb95eed0e1' * * 43 78 eb bb 95 ee d0 e1 big endian * e1 d0 ee 95 bb eb 78 43 little endian * bb eb 78 43 e1 d0 ee 95 mixed endian * * Rounds to 112233445566778896.0. */ p_u8 = (volatile uint8_t *) p_dbl; printf("%02x %02x %02x %02x %02x %02x %02x %02x = %lf\n", (unsigned int) p_u8[0], (unsigned int) p_u8[1], (unsigned int) p_u8[2], (unsigned int) p_u8[3], (unsigned int) p_u8[4], (unsigned int) p_u8[5], (unsigned int) p_u8[6], (unsigned int) p_u8[7], *p_dbl); if (p_u8[0] == 0x43 && p_u8[1] == 0x78 && p_u8[2] == 0xeb && p_u8[3] == 0xbb && p_u8[4] == 0x95 && p_u8[5] == 0xee && p_u8[6] == 0xd0 && p_u8[7] == 0xe1) { printf("big endian\n"); } else if (p_u8[0] == 0xe1 && p_u8[1] == 0xd0 && p_u8[2] == 0xee && p_u8[3] == 0x95 && p_u8[4] == 0xbb && p_u8[5] == 0xeb && p_u8[6] == 0x78 && p_u8[7] == 0x43) { printf("little endian\n"); } else if (p_u8[0] == 0xbb && p_u8[1] == 0xeb && p_u8[2] == 0x78 && p_u8[3] == 0x43 && p_u8[4] == 0xe1 && p_u8[5] == 0xd0 && p_u8[6] == 0xee && p_u8[7] == 0x95) { printf("mixed endian\n"); } else { printf("unknown endian\n"); } } else { goto usage; } exit(0); usage: fprintf(stderr, "Usage: ./check_align (uint16_t|uint32_t|uint64_t|double) \n"); exit(1); }