C - Write struct to NVM byte by byte - c
I have a struct of different data types, which should be written into the non-volatile memory. It is possible to write it word after word, but I'm unsure, how I can read a word from my struct.
The struct looks like this:
typedef struct
{
uint8_t value1;
int16_t value2;
uint32_t value3;
float value4;
} __attribute__(( aligned(4))) test_struct_t;
How is it possible, to write word by word from this struct? With the aligned(4) attribute this should be possible, right?
How is it possible, to write word by word from this struct? With the aligned(4) attribute this should be possible, right?
Hmm, no, the answer to that is that writing the struct to a non-volatile storage system using 32bit "words" would make the resulting data unportable across systems due to possible Byte Endianness concerns.
EDIT: If the data isn't going anywhere
If the stored data isn't leaving the system, Endianness isn't an issue and that part of my original answer (further on) can be safely ignored.
I would still consider manually marking the padding in the struct and updating the naming as detailed below (see: Ease of use / Portability).
Also, if the NVM has a memory address and the standard library is available (or a compiler builtin function) - memcpy will be a simple solution and there's no need to worry about alignments and other implementation details.
Can we use a uint32_t *?
The issue is that if we use a pointer that violates the standard (invokes undefined behavior), than the compiler is free to assume that the data in the struct was never (properly) accessed and optimize away our read/write operations.
For example, this might leave us with old data in the struct even though we thought we performed a "read" operation (that was optimized away).
There is a good solution offered in #Lundin's answer.
Lundin's solution is one way to deal with the restrictions stated in section 6.5 (paragraph 7) of the C11 standard - restrictions that C compilers rely upon when optimizing your code:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
...
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
A similar issue occurs in section 6.2.7 (paragraph 2) of the standard:
declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
#Lundin's approach uses a union type, which is the second to last solution. My approach used the last approach (a char type) when storing the data.
Another approach would use void * to move the calculation to an independent function (same approved as memcpy). This will prevent the compiler from assuming anything as void * conversions are always allowed.
Original Answer:
I think the problem of writing to non-volatile storage is divided into 2 main issues:
Byte Endianness - different systems have different memory models and we want the non-volatile storage to be as system agnostic as possible.
Ease of use / Portability - we don't want to rewrite a lot of pieces of code every time we update the structure and we want to minimize compiler specific instructions.
Byte Endiannes
If we store the data on one system and than load it in another system, the byte ordering may be different between systems, breaking our data scheme.
To solve Byte Endiannes it's important to read and store 32bit numbers and 16 bit numbers in a way that is byte order agnostic. This means storing the specific bits in a pre-determined bytes.
I wrote a few macros for that (based on the facil.io open source framework):
/** write uint16_t to a buffer independently of system's of endieness. */
#define u2buf16(dest, i) \
do { \
((uint8_t *)(dest))[0] = ((uint16_t)(i)) & 0xFF; \
((uint8_t *)(dest))[1] = (((uint16_t)(i)) >> 8) & 0xFF; \
} while (0)
/** write uint32_t to a buffer independently of system's of endieness. */
#define u2buf32(dest, i) \
do { \
((uint8_t *)(dest))[0] = ((uint32_t)(i)) & 0xFF; \
((uint8_t *)(dest))[1] = (((uint32_t)(i)) >> 8) & 0xFF; \
((uint8_t *)(dest))[2] = (((uint32_t)(i)) >> 16) & 0xFF; \
((uint8_t *)(dest))[3] = (((uint32_t)(i)) >> 24) & 0xFF; \
} while (0)
/** read uint16_t from a buffer independently of system's of endieness. */
#define buf2u16(src) \
((uint16_t)(((uint8_t *)(src))[0]) | ((uint16_t)(((char *)(src))[1]) << 8))
/** read uint32_t from a buffer independently of system's of endieness. */
#define buf2u32(src) \
(((uint32_t)(((uint8_t *)(src))[0])) | \
(((uint32_t)(((uint8_t *)(src))[1])) << 8) | \
(((uint32_t)(((uint8_t *)(src))[2])) << 16) | \
(((uint32_t)(((uint8_t *)(src))[3])) << 24))
Ease of use / Portability
The best way to deal with this is to encapsulate the code in proper functions.
Before I did that, I updated the example in a number of small ways:
I removed the __attribute__(( aligned(4))) instruction, as it's both compiler specific and unnecessary.
I renamed the struct's postfix from _t to _s.
The _t type postfix is reserved by the POSIX standard and mustn't be used in user-code.
The _s postfix is a common way to indicate struct (or _u for unions, and _p for pointers, etc'). This is a personal preference and depends on where you work.
I added a uint8_t reserved; field where padding would have naturally occurred, both making room for future updates and making sure no unknown padding was present in the struct (here I use this quality only during testing).
This came out as:
typedef struct {
uint8_t value1;
uint8_t reserved; /* reserved for future versions */
int16_t value2;
uint32_t value3;
float value4;
} test_struct_s;
For the function decelerations (API) I used the root of the type name (test_struct) as the name spaced appended the function names at the end.
This approach too is a common way to manage namespaces and is a personal preference that depends on the guidelines in your workspace.
They came up as:
static void test_struct_write(char *dest, test_struct_s *src);
static void test_struct_read(test_struct_s *dest, char *src);
Now, the first thing to do is to write tests for the code.
By writing a bit in every byte before a read/write roundtrip, it is possible to effectively test the read/write roundtrip for correctness.
In addition, we want to make sure that each field in the tested struct had a different bit set, so we make sure to test that we're not mixing up values.
/** test read/write behavior. */
static void test_struct_rw_test(void) {
/*
* write defferent values to each struct field, making sure all bytes have a
* set bit at least once during the test.
*
* perform a read/write roundtri[ and test that the set bit has the same
* value.
*/
for (size_t i = 0; i < 32; ++i) {
union {
float f;
uint32_t i;
} u;
/* a float with a single bit set somewhere */
u.i = ((uint32_t)1U << ((i + 1) & 31));
/* a different bit is set in every struct field */
test_struct_s r, s = {
.value1 = (1U << ((i + 0) & 31)),
.reserved = (1U << ((i + 1) & 31)),
.value2 = (1U << ((i + 2) & 31)),
.value3 = (1U << ((i + 3) & 31)),
.value4 = u.f,
};
char buf[sizeof(s)];
test_struct_write(buf, &s);
test_struct_read(&r, buf);
/* we can use memcmp only because we control the padded bytes with
* `reserved` */
if (memcmp(&s, &r, sizeof(s))) {
fprintf(stderr, "FATAL: Read/Write rountrip test failed (at %zu)\n", i);
fprintf(stderr, "%u!=%u\n%u!=%u\n%d!=%d\n%u!=%u\n%f!=%f\n", s.value1,
r.value1, s.reserved, r.reserved, s.value2, r.value2, s.value3,
r.value3, s.value4, r.value4);
exit(-1);
}
}
}
Next we need to actually code the read / write functions themselves.
As you will notice, I am assigning each 8 bit sequence to a specific byte, allowing the code to be endianness and system agnostic.
The buffer being written to or read from MUST be (at least) 96 bits long (12 bytes), or the functions will overflow.
/** "safely" write test_struct_s to a buffer. buffer MUST be 96 bits long. */
static void test_struct_write(char *dest, test_struct_s *src) {
union {
float f;
uint32_t i;
} u;
if (sizeof(float) != sizeof(uint32_t))
goto system_error; /* will be tested by the compiler and optimized away... */
u.f = src->value4;
dest[0] = src->value1;
dest[1] = src->reserved;
u2buf16(dest + 2, src->value2);
u2buf32(dest + 4, src->value3);
u2buf32(dest + 8, u.i);
return;
system_error:
fprintf(stderr,
"FATAL: Program requires a modern system where floats are 32 bits "
"(sizeof(float) == %zu)\n",
sizeof(float));
exit(-1);
}
/** "safely" read test_struct_s from a buffer. buffer MUST be 96 bytes long. */
static void test_struct_read(test_struct_s *dest, char *src) {
if (sizeof(float) != sizeof(uint32_t))
goto system_error;
union {
float f;
uint32_t i;
} u;
dest->value1 = src[0];
dest->reserved = src[1];
dest->value2 = buf2u16(src + 2);
dest->value3 = buf2u32(src + 4);
u.i = buf2u32(src + 8);
dest->value4 = u.f;
return;
system_error:
fprintf(stderr,
"FATAL: Program requires a modern system where floats are 32 bits "
"(sizeof(float) == %zu)\n",
sizeof(float));
exit(-1);
}
And we're done.
The whole of the code looks something like this:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* added a `reserved` field to mark natural struct padding AND control padded
* bytes.
*
* now, sizeof(test_struct_s) == 96
*/
typedef struct {
uint8_t value1;
uint8_t reserved; /* reserved for future versions */
int16_t value2;
uint32_t value3;
float value4;
} test_struct_s;
static void test_struct_write(char *dest, test_struct_s *src);
static void test_struct_read(test_struct_s *dest, char *src);
/** write uint16_t to a buffer independently of system's of endieness. */
#define u2buf16(dest, i) \
do { \
((uint8_t *)(dest))[0] = ((uint16_t)(i)) & 0xFF; \
((uint8_t *)(dest))[1] = (((uint16_t)(i)) >> 8) & 0xFF; \
} while (0)
/** write uint32_t to a buffer independently of system's of endieness. */
#define u2buf32(dest, i) \
do { \
((uint8_t *)(dest))[0] = ((uint32_t)(i)) & 0xFF; \
((uint8_t *)(dest))[1] = (((uint32_t)(i)) >> 8) & 0xFF; \
((uint8_t *)(dest))[2] = (((uint32_t)(i)) >> 16) & 0xFF; \
((uint8_t *)(dest))[3] = (((uint32_t)(i)) >> 24) & 0xFF; \
} while (0)
/** read uint16_t from a buffer independently of system's of endieness. */
#define buf2u16(src) \
((uint16_t)(((uint8_t *)(src))[0]) | ((uint16_t)(((char *)(src))[1]) << 8))
/** read uint32_t from a buffer independently of system's of endieness. */
#define buf2u32(src) \
(((uint32_t)(((uint8_t *)(src))[0])) | \
(((uint32_t)(((uint8_t *)(src))[1])) << 8) | \
(((uint32_t)(((uint8_t *)(src))[2])) << 16) | \
(((uint32_t)(((uint8_t *)(src))[3])) << 24))
/** "safely" write test_struct_s to a buffer. buffer MUST be 96 bytes long. */
static void test_struct_write(char *dest, test_struct_s *src) {
union {
float f;
uint32_t i;
} u;
if (sizeof(float) != sizeof(uint32_t))
goto system_error;
u.f = src->value4;
dest[0] = src->value1;
dest[1] = src->reserved;
u2buf16(dest + 2, src->value2);
u2buf32(dest + 4, src->value3);
u2buf32(dest + 8, u.i);
return;
system_error:
fprintf(stderr,
"FATAL: Program requires a modern system where floats are 32 bits "
"(sizeof(float) == %zu)\n",
sizeof(float));
exit(-1);
}
/** "safely" read test_struct_s from a buffer. buffer MUST be 96 bytes long. */
static void test_struct_read(test_struct_s *dest, char *src) {
if (sizeof(float) != sizeof(uint32_t))
goto system_error;
union {
float f;
uint32_t i;
} u;
dest->value1 = src[0];
dest->reserved = src[1];
dest->value2 = buf2u16(src + 2);
dest->value3 = buf2u32(src + 4);
u.i = buf2u32(src + 8);
dest->value4 = u.f;
return;
system_error:
fprintf(stderr,
"FATAL: Program requires a modern system where floats are 32 bits "
"(sizeof(float) == %zu)\n",
sizeof(float));
exit(-1);
}
/** test read/write behavior. */
static void test_struct_rw_test(void) {
/*
* write defferent values to each struct field, making sure all bytes have a
* set bit at least once during the test.
*
* perform a read/write roundtri[ and test that the set bit has the same
* value.
*/
for (size_t i = 0; i < 32; ++i) {
union {
float f;
uint32_t i;
} u;
/* a float with a single bit set somewhere */
u.i = ((uint32_t)1U << ((i + 1) & 31));
test_struct_s r, s = {
.value1 = (1U << ((i + 0) & 31)),
.reserved = (1U << ((i + 1) & 31)),
.value2 = (1U << ((i + 2) & 31)),
.value3 = (1U << ((i + 3) & 31)),
.value4 = u.f,
};
char buf[sizeof(s)];
test_struct_write(buf, &s);
test_struct_read(&r, buf);
/* we can use memcmp only because we control the padded bytes with
* `reserved` */
if (memcmp(&s, &r, sizeof(s))) {
fprintf(stderr, "FATAL: Read/Write rountrip test failed (at %zu)\n", i);
fprintf(stderr, "%u!=%u\n%u!=%u\n%d!=%d\n%u!=%u\n%f!=%f\n", s.value1,
r.value1, s.reserved, r.reserved, s.value2, r.value2, s.value3,
r.value3, s.value4, r.value4);
exit(-1);
}
}
}
int main(void) {
test_struct_rw_test();
fprintf(stderr, "PASSED\n");
return 0;
}
The following solution seems to work fine:
test_struct_t test_t;
uint16_t size = sizeof(test_struct_t)/sizeof(uint32_t);
uint32_t *ptr = (uint32_t *)&test_t;
for(uint16_t i = 0; i < size; i++)
{
writeWordNVM(i, *ptr);
ptr++;
}
Apart from alignment, the issue here is the C type system, where each position in memory that contains a declared variable or has been de-referenced by the program through a value access, has an internal "type tag" formally known as effective type. This is used for optimization purposes, so that the compiler can know if pointer types of different kinds may alias. That is, if they could refer to the same memory location. Informally this whole set of rules is called the "strict aliasing rules". What is the strict aliasing rule?
Simple example of pointer aliasing: if you have void func (float* f){ *f = 1.0f; } and a global int foo;, the compiler is free to assume that the function writing to *f won't modify the contents of foo when doing so.
Traditionally, embedded system compilers never used optimization based on aliasing assumptions, but with gcc entering the embedded world, this is no longer necessarily the case. If you compile with gcc -fno-strict-aliasing, you can dodge the problem, but the code won't be portable.
This is kind of a language defect. To portably avoid the strict aliasing rules, you must use cumbersome tricks such as union type punning. That is, create a union containing the struct and an array of uint32_t both, then do all de-referencing on the array member. Example:
#include <stdio.h>
#include <stdint.h>
typedef struct
{
uint8_t value1;
int16_t value2;
uint32_t value3;
float value4;
} test_struct_t;
_Static_assert(_Alignof(test_struct_t) == _Alignof(uint32_t),
"Inconsistent alignment in test_struct_t");
typedef union
{
struct
{
uint8_t value1;
int16_t value2;
uint32_t value3;
float value4;
};
uint32_t u32 [sizeof(test_struct_t)/sizeof(uint32_t)];
} test_union_t;
int main(int argc, char **argv)
{
test_union_t test = {.value1 = 1, .value2 = 2};
printf("%.8X\n", test.u32[0]);
return 0;
}
Here I first made a typedef of the struct just to check with static assert if the alignment is ok, removing the non-standard __attribute__(( aligned(4))).
Then when creating the type punning union, I made the same struct anonymous just so that we don't have to type out test.test_struct.value1 rather than test.value1, kind of hiding the fact that it's a union.
I then initialized some members of the union by name and de-referenced them through a type punned uint32_t. This prints 00020001 on my little endian machine, apparently there's a padding byte after value1, which is as expected.
Related
Correct way of calling a c function that expects const char8 string[] as parameter
Inside an ISR of a microcontroller I am attempting to call a function as follows: //adc.c static volatile char uartBuf[6]={0}; CY_ISR(ISR_ADC) { for (uint8_t i=0; i < NS; i++) total += adc2_buffer0[i]; uartBuf[0] = total >> 24 & 0xFF; uartBuf[1] = total >> 16 & 0xFF; uartBuf[2] = total >> 8 & 0xFF; uartBuf[3] = total & 0xFF; uartBuf[4] = '\n'; UART_1_PutString(uartBuf); //doesn't work } //uart.c void UART_1_PutString(const char8 string[]) { ... } However in the function UART_1_PutString, string always points to '\0' rather than uartBuf? What could be the problem? Theoretically the variable uartBuf shouldn't be optimized out by the compiler.
The code seems correct Do you mean that string[0] == '\0'? Maybe (total >> 24 & 0xFF) == 0 always (or most of the times). EDIT: The function should be void UART_1_PutString(const volatile unsigned char buff[]); It shouldn't be called string, because it's not text, it's just a buffer (it looks like it at least). unsigned because the "string", comes from some unsigned bit manipulation after some maths, which could cause an invalid signed value (unlikely to fail, but the rule should be: char for text, unsigned char for unknown data (everything else)). volatile because if not, you are discarding the volatile qualifier. A compiler with high enough flags (in GCC: -Wall -Wextra -Werror will highlight almost everything as errors) will warn you about that. The compiler could think that the contents of the function can be simplified even before knowing that you will call it with volatile data, and therefore will optimize something which shouldn't be optimized. You could also add the restrict keyword (C11) if no other function will access that buffer at the same time, so that you help the compiler produce better code: void UART_1_PutString(const volatile unsigned char buff[restrict]); EDIT2: You should state the size of the buffer if it is only going to be called with that buffer, or also pass the size of the buffer to the function if not: void UART_1_PutString(const volatile unsigned char buff[restrict 6]); (6 should probably be replaced by some macro) or void UART_1_PutString(size_t size, const volatile unsigned char buff[restrict size]);
What does this macro return and how do use it?
I have a problem to understand how I can use this macro to get the lenght of the IP header. I have a file called framehdr.h and I have included that file in my main.c. The struct in the framehdr.h file look like this: struct ip_hdr { unsigned char vhl; /* Version and header length */ unsigned char tos; /* Type of service */ unsigned short len; /* Total length */ unsigned short id; /* Identification */ unsigned short off; /* Fragment offset field */ unsigned char ttl; /* Time to live */ unsigned char p; /* Protocol */ unsigned short ip_sum; /* Checksum */ unsigned int src, dst; /* Source and dest address */ }; I can manually get the lentgh by adding all the sizes like this: unsigned int sizeIP = sizeof(testOne.vhl) + sizeof(testOne.tos) + sizeof(testOne.len) + sizeof(testOne.id) + sizeof(testOne.off) + sizeof(testOne.ttl) + sizeof(testOne.p) + sizeof(testOne.ip_sum) + sizeof(testOne.src) + sizeof(testOne.dst); But I'm suppose to use the macro that look like this to get the size: #define IP_HL(ip) ((((ip)->vhl) & 0x0f) * 4) What does this macro return? Is it a digit so I can store it in a int and then print it or how does it work?
It looks like vhl (which is an 8 bit member, unless CHAR_BIT is a weird value on your platform) is used to store the version in the significant 4 bits and the header length in the other 4 bits. ((ip)->vhl) & 0x0f) extracts the least significant 4 bits of the vhl member of the struct to which ip is pointing. The multiplication by 4 to get the actual length is merely obeying the conventions of that member. The way you are using sizeof to "manually get the length" is making assumptions about the header length corresponding to the sum of the sizes of the individual members. Member padding and undocumented conventions centred around the serialisation technique used for your struct might mean this is not the case.
Wrong SHA-1 hash
I'm planning to use AVR-Crypto's SHA-1 implementation for HMAC. However, I can't seem to generate the correct SHA-1 sum. For instance, if I call the function with the following unsigned char sha1sum[20]; char *msg = "FFFFFFFFFF"; sha1( sha1sum, msg, strlen(msg)); I get 000000000000000000002C002312290000000029 rather than the expected c1bb92851109fe950a2655fa1d4ba1d04719f6fb. Does anyone know what might be wrong? Here's the AVR-Crypto's implementation #include <string.h> /* memcpy & co */ #include <stdint.h> #include "config.h" #include "debug.h" #include "sha1.h" #ifdef DEBUG # undef DEBUG #endif #include "cli.h" #define LITTLE_ENDIAN /********************************************************************************************************/ /** * \brief initialises given SHA-1 context * */ void sha1_init(sha1_ctx_t *state){ DEBUG_S("\r\nSHA1_INIT"); state->h[0] = 0x67452301; state->h[1] = 0xefcdab89; state->h[2] = 0x98badcfe; state->h[3] = 0x10325476; state->h[4] = 0xc3d2e1f0; state->length = 0; } /********************************************************************************************************/ /* some helping functions */ uint32_t rotl32(uint32_t n, uint8_t bits){ return ((n<<bits) | (n>>(32-bits))); } uint32_t change_endian32(uint32_t x){ return (((x)<<24) | ((x)>>24) | (((x)& 0x0000ff00)<<8) | (((x)& 0x00ff0000)>>8)); } /* three SHA-1 inner functions */ uint32_t ch(uint32_t x, uint32_t y, uint32_t z){ DEBUG_S("\r\nCH"); return ((x&y)^((~x)&z)); } uint32_t maj(uint32_t x, uint32_t y, uint32_t z){ DEBUG_S("\r\nMAJ"); return ((x&y)^(x&z)^(y&z)); } uint32_t parity(uint32_t x, uint32_t y, uint32_t z){ DEBUG_S("\r\nPARITY"); return ((x^y)^z); } /********************************************************************************************************/ /** * \brief "add" a block to the hash * This is the core function of the hash algorithm. To understand how it's working * and what thoese variables do, take a look at FIPS-182. This is an "alternativ" implementation */ #define MASK 0x0000000f typedef uint32_t (*pf_t)(uint32_t x, uint32_t y, uint32_t z); void sha1_nextBlock (sha1_ctx_t *state, const void *block){ uint32_t a[5]; uint32_t w[16]; uint32_t temp; uint8_t t,s,fi, fib; pf_t f[] = {ch,parity,maj,parity}; uint32_t k[4]={ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6}; /* load the w array (changing the endian and so) */ for(t=0; t<16; ++t){ w[t] = change_endian32(((uint32_t*)block)[t]); } #if DEBUG uint8_t dbgi; for(dbgi=0; dbgi<16; ++dbgi){ /* DEBUG_S("\n\rBlock:"); DEBUG_B(dbgi); DEBUG_C(':'); */ cli_putstr_P(PSTR("\r\nBlock:")); cli_hexdump(&dbgi, 1); cli_putc(':'); cli_hexdump(&(w[dbgi]) ,4); } #endif /* load the state */ memcpy(a, state->h, 5*sizeof(uint32_t)); /* the fun stuff */ for(fi=0,fib=0,t=0; t<=79; ++t){ s = t & MASK; if(t>=16){ #if DEBUG DEBUG_S("\r\n ws = "); cli_hexdump(&(w[s]), 4); #endif w[s] = rotl32( w[(s+13)&MASK] ^ w[(s+8)&MASK] ^ w[(s+ 2)&MASK] ^ w[s] ,1); #ifdef DEBUG DEBUG_S(" --> ws = "); cli_hexdump(&(w[s]), 4); #endif } uint32_t dtemp; temp = rotl32(a[0],5) + (dtemp=f[fi](a[1],a[2],a[3])) + a[4] + k[fi] + w[s]; memmove(&(a[1]), &(a[0]), 4*sizeof(uint32_t)); /* e=d; d=c; c=b; b=a; */ a[0] = temp; a[2] = rotl32(a[2],30); /* we might also do rotr32(c,2) */ fib++; if(fib==20){ fib=0; fi = (fi+1)%4; } #if DEBUG /* debug dump */ DEBUG_S("\r\nt = "); DEBUG_B(t); DEBUG_S("; a[]: "); cli_hexdump(a, 5*4); DEBUG_S("; k = "); cli_hexdump(&(k[t/20]), 4); DEBUG_S("; f(b,c,d) = "); cli_hexdump(&dtemp, 4); #endif } /* update the state */ for(t=0; t<5; ++t){ state->h[t] += a[t]; } state->length += 512; } /********************************************************************************************************/ void sha1_lastBlock(sha1_ctx_t *state, const void *block, uint16_t length){ uint8_t lb[SHA1_BLOCK_BYTES]; /* local block */ while(length>=SHA1_BLOCK_BITS){ sha1_nextBlock(state, block); length -= SHA1_BLOCK_BITS; block = (uint8_t*)block + SHA1_BLOCK_BYTES; } state->length += length; memset(lb, 0, SHA1_BLOCK_BYTES); memcpy (lb, block, (length+7)>>3); /* set the final one bit */ lb[length>>3] |= 0x80>>(length & 0x07); if (length>512-64-1){ /* not enouth space for 64bit length value */ sha1_nextBlock(state, lb); state->length -= 512; memset(lb, 0, SHA1_BLOCK_BYTES); } /* store the 64bit length value */ #if defined LITTLE_ENDIAN /* this is now rolled up */ uint8_t i; for (i=0; i<8; ++i){ lb[56+i] = ((uint8_t*)&(state->length))[7-i]; } #elif defined BIG_ENDIAN *((uint64_t)&(lb[56])) = state->length; #endif sha1_nextBlock(state, lb); } /********************************************************************************************************/ void sha1_ctx2hash (void *dest, sha1_ctx_t *state){ #if defined LITTLE_ENDIAN uint8_t i; for(i=0; i<5; ++i){ ((uint32_t*)dest)[i] = change_endian32(state->h[i]); } #elif BIG_ENDIAN if (dest != state->h) memcpy(dest, state->h, SHA1_HASH_BITS/8); #else # error unsupported endian type! #endif } /********************************************************************************************************/ /** * * */ void sha1 (void *dest, const void *msg, uint32_t length){ sha1_ctx_t s; DEBUG_S("\r\nBLA BLUB"); sha1_init(&s); while(length & (~0x0001ff)){ /* length>=512 */ DEBUG_S("\r\none block"); sha1_nextBlock(&s, msg); msg = (uint8_t*)msg + SHA1_BLOCK_BITS/8; /* increment pointer to next block */ length -= SHA1_BLOCK_BITS; } sha1_lastBlock(&s, msg, length); sha1_ctx2hash(dest, &s); } Here's the header: #ifndef SHA1_H_ #define SHA1_H_ #include "stdint.h" /** \def SHA1_HASH_BITS * definees the size of a SHA-1 hash in bits */ /** \def SHA1_HASH_BYTES * definees the size of a SHA-1 hash in bytes */ /** \def SHA1_BLOCK_BITS * definees the size of a SHA-1 input block in bits */ /** \def SHA1_BLOCK_BYTES * definees the size of a SHA-1 input block in bytes */ #define SHA1_HASH_BITS 160 #define SHA1_HASH_BYTES (SHA1_HASH_BITS/8) #define SHA1_BLOCK_BITS 512 #define SHA1_BLOCK_BYTES (SHA1_BLOCK_BITS/8) /** \typedef sha1_ctx_t * \brief SHA-1 context type * * A vatiable of this type may hold the state of a SHA-1 hashing process */ typedef struct { uint32_t h[5]; // uint64_t length; uint8_t length; } sha1_ctx_t; /** \typedef sha1_hash_t * \brief hash value type * A variable of this type may hold a SHA-1 hash value */ /* typedef uint8_t sha1_hash_t[SHA1_HASH_BITS/8]; */ /** \fn sha1_init(sha1_ctx_t *state) * \brief initializes a SHA-1 context * This function sets a ::sha1_ctx_t variable to the initialization vector * for SHA-1 hashing. * \param state pointer to the SHA-1 context variable */ void sha1_init(sha1_ctx_t *state); /** \fn sha1_nextBlock(sha1_ctx_t *state, const void *block) * \brief process one input block * This function processes one input block and updates the hash context * accordingly * \param state pointer to the state variable to update * \param block pointer to the message block to process */ void sha1_nextBlock (sha1_ctx_t *state, const void *block); /** \fn sha1_lastBlock(sha1_ctx_t *state, const void *block, uint16_t length_b) * \brief processes the given block and finalizes the context * This function processes the last block in a SHA-1 hashing process. * The block should have a maximum length of a single input block. * \param state pointer to the state variable to update and finalize * \param block pointer to themessage block to process * \param length_b length of the message block in bits */ void sha1_lastBlock (sha1_ctx_t *state, const void *block, uint16_t length_b); /** \fn sha1_ctx2hash(sha1_hash_t *dest, sha1_ctx_t *state) * \brief convert a state variable into an actual hash value * Writes the hash value corresponding to the state to the memory pointed by dest. * \param dest pointer to the hash value destination * \param state pointer to the hash context */ void sha1_ctx2hash (void *dest, sha1_ctx_t *state); /** \fn sha1(sha1_hash_t *dest, const void *msg, uint32_t length_b) * \brief hashing a message which in located entirely in RAM * This function automatically hashes a message which is entirely in RAM with * the SHA-1 hashing algorithm. * \param dest pointer to the hash value destination * \param msg pointer to the message which should be hashed * \param length_b length of the message in bits */ void sha1(void *dest, const void *msg, uint32_t length_b); #endif /*SHA1_H_*/ UPDATE If I initialise sha1sum with unsigned char sha1sum[20] = 0;, the resulting sum is all 0x00.
There are at least two bugs in the question's code (detailed below), but neither can explain the result shown, and the added fact that unsigned char sha1sum[20] = {0} in the calling code changes the result. Something is wrong with the translation from the C source code that we read into machine code! Most likely, sha1_ctx2hash did not write where it should. Problem could be in a header not in the question, a compiler bug... Since we are on a 8051, that could be/have been a problem with pointer types, especially in the pointer casts that MUST be to a pointer of the same size. Also, is it dead sure the 8051 compiler is little-endian? It seems the common Keil C51 uses big-endian convention. That's an arbitrary choice of the compiler+support library, since on the original 8051 there is no multi-byte data-related instruction, the closest thing is LCALL which stack pushes are little-endian, but LJMP and MOV DPTR,# code is big-endian. Update: We are told the compiler is by IAR. According to IAR's documentation, version 5 was big-endian, and that changed to little-endian in version 6. Update: we found another critical issue (beyond likely unsafe pointer casting, and the two bugs discussed below). At some point in the hunt, replacing the code with a single procedure having no endianness dependency or pointer cast, the output became 0000eb1700007f3d000004f0000059290000fc21 and that suggested would-be-32-bit values are truncated to 16-bit. Indeed, the OP revealed: I have this in my stdint.h: typedef unsigned uint32_t; This is correct only on compilers where unsigned int is exactly 32-bit, when the only insurance given by the C standard is that it is at least 16-bit, and that minimum is used by most C compilers for less-than-32-bit CPUs (for efficiency reasons; some even have an option to disable promotion of byte operands to integer, and are even happy with 80+80+96 being 0). Bug in the test code: sha1( sha1sum, msg, strlen(msg)) should be sha1( sha1sum, msg, strlen(msg)*8) or the like, because the length parameters is in bits. Bug in the sha1_lastBlock w.r.t. header file: the code reading for (i=0; i<8; ++i){ lb[56+i] = ((uint8_t*)&(state->length))[7-i]; } assumes that state->length is 8 bytes, when it is not, because uint64_t length was changed to uint8_t length in the header (it is common that uint64_t is not available on 8051 compilers). The code for the big-endian case (not presently compiled) is affected too. If indeed uint8_t length and thus a restriction to length of 31 bytes at most is acceptable, both the little-endian and big-endian cases reduce to lb[SHA1_BLOCK_BYTES-1] = state->length; (without a loop). Or, for whatever unsigned type and endianness length might use: for (i = SHA1_BLOCK_BYTES; state->length != 0; state->length >>= 8) lb[--i] = (uint8_t)(state->length); Note: The code *((uint64_t*)&(lb[56])) = state->length was writing the 8 bytes of length to the end of array lb[], but is correct only on big-endian machines with proper uint64_t. The code has as potential extra problem when (length+7)%8 < 6: at least one bit in the last byte to hash is not masked, and if set it enters the hash and makes it wrong. That won't harm in the use case where full bytes are hashed. The original code might be correct (except for the above potential extra problem), but is needlessly complex given that the objective is hashing in-memory data with a single call (what sha1 does), and neither compact nor readable. Among other issues: there is (rightly) a block loop in sha1_lastBlock, thus the restriction worded in the header The block should have a maximum length of a single input block does not exist; that makes the other block loop in sha1 redundant; both of these loops can be removed if using uint8_t length, or otherwise hashing less than 56 bytes; the round loop is likely slowed by a memmove of 16 bytes, and a function call in a vector from an indexed table; endianness conversion in the little-endian case is rather inefficient; in sha1_ctx2hash, the #elif BIG_ENDIAN triggers an error in my mental compiler, since BIG_ENDIAN seems undefined and #elif is supposed to have an argument; that should be #elif defined BIG_ENDIAN (as used a few lines above); pf_t f[] = {ch,parity,maj,parity}; is a good candidate for const, perhaps static: every C compiler for 8051 that I ever used won't recognize that the array is not changed after setup, and thus can be carved in code; with such compilers, needlessly using function pointers (as above) is a tried and test method to harm performance, or worse; at the very least it blocks the analysis of the call tree, needed to allocate automatic variables at static addresses with overlay, which in turn improves performance and code size significantly. If you are after speed, the code you start from is inadequate, and nothing will quite match assembly language. Like two decades ago I wrote SHA-1 for some 8051 toolchain, and assembly tuneups gave huge savings compared to C only (IIRC: mostly because 32-bit rotations where abyssal from a performance standpoint). Updated: Here is illustrative code to hash a short message, in an endian-neutral way, without any pointer cast, and without depending on <stdint.h> (which turns out to be inadequate for the compiler used). Beware that the length parameter is in bytes (not bits), with a limit of 55 bytes that does NOT allow implementing HMAC-SHA-1 on top. That's to keep the code simple: over that limit we need several iterations of the compression function, thus either heavy code duplication, at least two functions, or some sort of state machine. #include <limits.h> // for UCHAR_MAX, UINT_MAX, ULONG_MAX // Compute the SHA-1 hash of a short msg, of length at most 55 bytes // Result hash must be 20 bytes; it can overlap msg. // CAUTION: if length>55 the result is wrong, and if length>59 // we loose second-preimage resistance, thus collision-resistance. void sha1upto55bytes( unsigned char *hash, // result, 20 bytes const unsigned char *msg, // bytes to hash unsigned char length // length of msg in bytes, maximum 55 ) { // We locally (re)define uint8_t and uint32_t so as not to depend of <stdint.h> // which is not available on some old C compilers for embedded systems. #if 255==UCHAR_MAX typedef unsigned char uint8_t; #endif #if 16383==UINT_MAX>>9>>9 typedef unsigned int uint32_t; #elif 16383==ULONG_MAX>>9>>9 typedef unsigned long uint32_t; #endif // Internal buffer (64 bytes) // We require 8-bit uint8_t, 32-bit uint32_t, and integer promotion; otherwise, // we try to abort compilation on the following declaration. uint32_t w[ 99==(uint8_t)355 && // check uint8_t 4303==(uint32_t)(-1)/999u/999 && // check uint32_t 440==(uint8_t)55<<3 // check integer promotion ? 16 : -1]; // negative index if error // Type for state, so that we can use struct copy for that typedef struct state_t { uint32_t q[5]; } state_t; // Initial state; use single quotes if the compiler barks const state_t s = {{ 0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0 }}; // Active state (20 bytes); on 8051 should be in internal RAM for best performance state_t h = s; // initialize the state using a struct copy // Workhorse temporary; on 8051 should be in internal RAM for best performance uint32_t x; // Workhorse index; on 8051 should be a register for performance uint8_t j; // Prepare the single block to hash; this code works regardless of endianness, // and does not perform misaligned memory accesses if msg is misaligned. x = 0; // This is only to prevent a bogus compiler warning j = 0; do { // for each block byte, up to and including high 4 bytes of length x <<= 8; if (j < length) x |= *msg++; // message byte else if (j == length) x |= 0x80; // padding byte if ((j&3)==3) w[j >> 2] = x; } while (++j!=60); w[15] = length << 3; // length in bits, needs integer promotion for length>31 // Hash that block j = 0; do { // round loop, run 80 times do { // dummy loop (avoid a goto) if (j<40) { if (j<20) { // for rounds 0..19 x = (((h.q[2] ^ h.q[3])&h.q[1]) ^ h.q[3]) + 0x5A827999; break; // out of dummy loop } else x = 0x6ED9EBA1; // for rounds 20..39 } else { if (j<60) { // for rounds 40..59 x = (h.q[1] | h.q[2])&h.q[3]; x |= h.q[1] & h.q[2]; x += 0x8F1BBCDC; break; } else x = 0xCA62C1D6; // for rounds 60..79 } // for rounds 20..39 and 60..79 x += h.q[1] ^ h.q[2] ^ h.q[3]; } while (0); // end of of dummy loop // for all rounds x += (h.q[0] << 5) | (h.q[0] >> 27); x += h.q[4]; h.q[4] = h.q[3]; h.q[3] = h.q[2]; h.q[2] = (h.q[1] << 30) | (h.q[1] >> 2); h.q[1] = h.q[0]; h.q[0] = x; x = w[j & 15]; if (j>=16) { // rounds 16..79 x ^= w[(j + 2) & 15]; x ^= w[(j + 8) & 15]; x ^= w[(j + 13) & 15]; w[j & 15] = x = (x << 1) | (x >> 31); } h.q[0] += x; // for all rounds } while (++j != 80); // The five final 32-bit modular additions are made in the next loop, and // reuse the constants (rather than a RAM copy), saving code and RAM. // Final addition and store result; this code works regardless of endianness, // and does not perform misaligned memory accesses if hash is misaligned. j = 0; do { x = h.q[j] + s.q[j]; // final 32-bit modular additions *hash++ = (uint8_t)(x>>24); *hash++ = (uint8_t)(x>>16); *hash++ = (uint8_t)(x>> 8); *hash++ = (uint8_t)(x ); } while (++j != 5); }
C function crashed at array parameter
I write a function like: void func1(char chx[], int y) { int wsn = 0; wsn = *(int *) (&chx[2]); if (wsn == 0) { ... } } Compiler works well, no warning, no error. But when the code is running, seems it get a wild pointer. the code crashed. But code like the following works well: wsn = (chx[5]<< 24) + (chx[4] << 16) + (chx[3] << 8) + chx[2]; Wonder why it was crashed
As I observed in a comment to the question, some machines don't like it if you pass a misaligned address and try to treat it as an int *. For example, many RISC machines require the address of a 4-byte quantity to be aligned on a 4-byte boundary, but an arbitrary char *is not necessarily sufficiently aligned. If you get a SIGBUS error instead of a SIGSEGV, this is often strongly indicative of the trouble. Since the Renesas site prominently mentions 'RISC' and Wikipedia affirms this, I am moderately confident that your problem is that the address passed to func1() is not sufficiently well aligned for &chx[2] to be valid as a 4-byte (presumably) int *. Your code doing the byte operations works because it only requires the data to be byte aligned, and all data on a byte-addressed machine is byte aligned. You could consider using: void func1(char chx[], int y) { int wsn = 0; int *ip = (int *)&chx[2]; if ((uintptr_t)ip & 0x3 == 0) wsn = *ip; else wsn = (chx[5]<< 24) + (chx[4] << 16) + (chx[3] << 8) + chx[2]; if (wsn == 0) { … } } But you may do just as well with the shift expression anyway. One thing to watch, though; those + operators should perhaps be | operators, especially if plain char is a signed type. If it works as it stands, then plain char is probably an unsigned type. Both are allowed by standard C, but which is used has to be documented.
Error trying to define a 1,024-bit (128 Byte) Bit Field
I would like to define a large bitfield for the purpose of quickly monitoring the status a very large structure of elements. Here is what I have so far: #define TOTAL_ELEMENTS 1021 typedef struct UINT1024_tag { UINT8 byte[128]; } UINT1024; typedef struct flags_tag { UINT1024:TOTAL_ELEMENTS; } flags_t; When I try compiling this, I get the error message, "error: bit-field `<anonymous>' has invalid type" Can bit-fields only be used on certain types? I thought that if I defined a large-enough variable, the massive bitfield needed for my application could then be defined because the bitfield has to be no larger than the type used to define it. Any thoughts or suggestions would be appreciated.
Bit fields must fit within a single int, you can't use arbitrary sizes. Honestly the ANSI bitfield implementation is kinda broken. It misses a lot of other stuff too, like control over padding and layout that real-world applications usually need. I'd consider writing some macros or accessor functions to abstract the larger sizes and giving up on the bitfield syntax.
In standard C language bit-fields can only be defined with a restricted set of types. In C89/90 these types are limited to int, signed int and unsigned int (a little-known detail is that in this context int is not guaranteed to be equivalent to signed int). In C99 type _Bool was added to the supported set. Any other types cannot be used in bit-field declaration. In practice, as a popular extension, compilers normally allow any integral type (or also enum type) in bit-field declaration. But a struct type... No, I'm not aware of any compiler that would allow that (let alone that it doesn't seem to make much sense).
use UINT128 blaha; You're not defining a bitfield. I'm not sure you understand what a bitfield is. I bitfield is a number of bits. Not an array of structs or similar. What exactly are you expecting that your code should do? Edit: oh I see now. No, you can't use your own types, just ints. Try this (untested code): struct bit1024 { unsigned char byte[128]; }; struct bit1024 foo; void set(struct bit1024*lala, int n, int v) { lala->byte[n/8] |= 1<<(n % 8); if (!v) { lala->byte[n/8] ^= 1<<(n % 8); } } int get(struct bit1024*lala, int n) { return 1 & (lala->byte[n/8] >> (n % 8)); }
As other have said, the C standard doesn't allow bit-fields to exceed the size of their attached integer type. I'd suggest using plain arrays with some macro magic: #include <limits.h> #include <stdio.h> #include <string.h> // SIZE should be a constant expression // this avoids VLAs and problems resulting from being evaluated twice #define BITFIELD(SIZE, NAME) \ unsigned char NAME[(SIZE) / CHAR_BIT + ((SIZE) % CHAR_BIT != 0)] static inline void setbit(unsigned char field[], size_t idx) { field[idx / CHAR_BIT] |= 1u << (idx % CHAR_BIT); } static inline void unsetbit(unsigned char field[], size_t idx) { field[idx / CHAR_BIT] &= ~(1u << (idx % CHAR_BIT)); } static inline void togglebit(unsigned char field[], size_t idx) { field[idx / CHAR_BIT] ^= 1u << (idx % CHAR_BIT); } static inline _Bool isbitset(unsigned char field[], size_t idx) { return field[idx / CHAR_BIT] & (1u << (idx % CHAR_BIT)); } int main(void) { BITFIELD(1025, foo); printf("sizeof foo = %u\n", sizeof foo); memset(foo, 0, sizeof foo); printf("%i", isbitset(foo, 1011)); setbit(foo, 1011); printf("%i", isbitset(foo, 1011)); unsetbit(foo, 1011); printf("%i", isbitset(foo, 1011)); } Hopefully, I didn't mess up the bit ops...