Why I get a '__packed__' attribute ignored [-Wattributes] warning in an android NDK Project?
Here is the code
mem_ = malloc(size_);
uint8_t* ui8_ptr = reinterpret_cast<uint8_t*>(mem_);
*ui8_ptr++ = packet_version;
//uint32_t* ui32_ptr = reinterpret_cast<uint32_t*>(ui8_ptr);
__packed uint32_t* ui32_ptr = (__packed uint32_t*)(ui8_ptr);
*ui32_ptr++ = size_;
*ui32_ptr++ = flags;
I am using the packed attribute because I think I have alignment problem when casting from uint8_t to uint32_t (See [1]).
[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
GCC doesn't seem to support the packed attribute for all variables. It is only supported for struct, union, and enum types. So you could try something like this instead:
mem_ = malloc(size_);
uint8_t* ui8_ptr = reinterpret_cast<uint8_t*>(mem_);
*ui8_ptr++ = packet_version;
struct unaligned32_t
{
uint32_t data __attribute__((packed, aligned(1)));
};
//unaligned32_t* ui32_ptr = reinterpret_cast<unaligned32_t*>(ui8_ptr);
unaligned32_t* ui32_ptr = (unaligned32_t*)(ui8_ptr);
(ui32_ptr++)->data = size_;
(ui32_ptr++)->data = flags;
This won't produce the warning unless you use it on a char type, which is already byte aligned anyway.
I'm still investigating if this produces the code I'm aiming for on my ARM micro-controller but it is the only legal way I can think of using the packed attribute.
Here be dragons! Don't take the address of unaligned32_t.data. You should only access the data member of the struct using the . or -> directly, and not via a pointer. See this answer for why.
Link you referenced is for RVDS compiler (probably armcc) and GCC doesn't support packed attribute on pointers for such usage.
Related
I am trying to port a code base from iar to avr-gcc. Amongst other things that have to replaced, the iar eeprom memory attribute __eeprom has to replaced with a avr-gcc friendly attribute. AFAIK the replacement for that is EEMEM, but the usage differs and I am not able to figure out how to replace __eeprom in the cleanest manner.
../src/myfunc.h:35:46: error: section attribute not allowed for 'src'
UBYTE *strcpye(UBYTE *dest, UBYTE EEMEM *src);
This error is not limited to pointers, but to all variables in general. IMO the usage of EEMEM is correct, where am I going wrong?
In the avr-gcc toolchain, avr-libc defines macro EEMEM in avr/eeprom.h:
#define EEMEM __attribute__((section(".eeprom")))
This means it's just an attribute that determines the section in which an object with this attribute will be located. In particular, EEMEM only makes sense for variables in static storage. Moreover, accesses to objects located in EEMEM have to be done by hand using functions / macros supplied by avr/eeprom.h like
void eeprom_read_block (void *dst, const void *src, size_t n);
void eeprom_write_byte (uint8_t *p, uint8_t value);
void eeprom_update_word (uint16_t *p, uint16_t value);
etc. Also notice that EEMEM is just an attribute and not a qualifier (like __flash for example). This means that even though you can tag a pointer (target) using attributes, that won't change the access in any way. To be more specific, any access through a pointer that's attributed EEMEM will be to RAM and not to eeprom.
In your case, the prototype of strcpye would read
char* strcpye (char *dest, const char *src);
and the implementation of that function would apply eeprom_read_byte on src++ and write to dest++ until it reads a terminal \0. Notice that you might need an explicit pointer cast as eeprom_read_byte expects [const] uint8_t*, and that char, signed char and unsigned char are 3 distinct types in C.
[skip to UPDATE2 and save some time :-)]
I use ARM Cortex-M4, with CMSIS 5-5.7.0 and FreeRTOS, compiling using GCC for ARM (10_2021.10)
My variables are not initialized as they should.
My startup code is pretty simple, the entry point is the reset handler (CMSIS declared startup_ARMCM4.s as deprecated and recommend using the C code startup code so this is what I do).
Here is my code:
__attribute__((__noreturn__)) void Reset_Handler(void)
{
DataInit();
SystemInit(); /* CMSIS System Initialization */
main();
}
static void DataInit(void)
{
typedef struct {
uint32_t const* src;
uint32_t* dest;
uint32_t wlen;
} __copy_table_t;
typedef struct {
uint32_t* dest;
uint32_t wlen;
} __zero_table_t;
extern const __copy_table_t __copy_table_start__;
extern const __copy_table_t __copy_table_end__;
extern const __zero_table_t __zero_table_start__;
extern const __zero_table_t __zero_table_end__;
for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) {
for(uint32_t i=0u; i<pTable->wlen; ++i) {
pTable->dest[i] = pTable->src[i];
}
}
for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) {
for(uint32_t i=0u; i<pTable->wlen; ++i) {
pTable->dest[i] = 0u;
}
}
}
__copy_table_start__, __copy_table_end__ etc. have the wrong values an so no data is copied to the appropriate place in RAM.
I tried adding __libc_init_array() before DataInit(), as suggested in this answer, and remove the nostartfiles flag from the linker, but at some point __libc_init_array() jumps to an illegal address and I get a HardFault interrupt.
Is there a different method to fix it? maybe one where I can use the nostartfiles flag?
UPDATE:
Looking at the memory, where __copy_table_start__ is located, I see the data there is valid (even without the use of __libc_init_array()). It seems that pTable doesn't get the correct value.
I tried using __data_start__, __data_end__, __bss_start__, __bss_end__ and __etext instead of the above variables, in the linker file it is said they can be used in code without definition, but they cannot (maybe that's a clue?). In any case they didn't work either.
UPDATE2:
found the actual problem
all struct members get the same value (modifying one changes all others), it happens with every struct. I have no idea how this is possible. In other words the value of __copy_table_start__.src is, for example, 0x14651234, __copy_table_start__.dest is 0x00100000, and __copy_table_start__.wlen is 0x0365. When looking at pTable all members are 0x14651234.
Using C++11, g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18).
Lets pretend I have a templated function (pardon my terminology if it isn't quite right).
I want to perform a "general" algorithm based on what was supposed to be compile-time instances of "field". Where the only things that really changed are these constants which I moved into trait classes (only added one here but imagine there are more). Originally I was declaring it as
constexpr field FIELD1{1};
However in C++11, non-type template params need to have external linkage (unlike C++14 which can have internal and external linkage?). So because not's in the same translation unit I needed to use extern in order to give it external linkage (sorry if I butchered that explanation also). But by defining it extern I can't define it using constexpr and it seems that losing that constexpr constructor this field is no longer a valid constant expression to qualify as a non-type template param.
Any suggestions if there is some way I can get around this? Open to a new method of doing things. Below is a simplified (incomplete, and non-compiling version to get the gist of the organization).
So the error I am seeing is along the lines of
error: the value of ‘FIELD1’ is not usable in a constant expression
note: ‘FIELD1’ was not declared ‘constexpr’
extern const field FIELD1;
Not quite sure what could be a best alternative.
I can get rid of the second error by removing the constexpr from the constructor. But then I don't know how to approach the constant expression issue.
field.H
struct field
{
int thingone;
constexpr field(int i):thingone(i){}
};
extern const field FIELD1;
field.C
#include "field.H"
const field FIELD1{0};
field_traits.H
#include "field.H"
template< const field& T >
class fieldTraits;
template< >
class fieldTraits<FIELD1>
{
public:
// Let's say I have common field names
// with different constants that I want to plug
// into the "function_name" algorithm
static constexpr size_t field_val = 1;
};
function.H
#include "field.H"
template< const field& T, typename TT = fieldTraits<T> >
void function_name()
{
// Let's pretend I'm doing something useful with that data
std::cout << T.thingone << std::endl;
std::cout << TT::field_val << std::endl;
}
So because not's in the same translation unit I needed to use extern in order to give it external linkage (sorry if I butchered that explanation also). But by defining it extern I can't define it using constexpr [...]
Per my comment, you can. It wouldn't work for you, but it's a step that helps in coming up with something that would work:
extern constexpr int i = 10;
This is perfectly valid, gives i external linkage, and makes i usable in constant expressions.
But it doesn't allow multiple definitions, so it can't work in a header file which is included in multiple translation units.
Ordinarily, the way around that is with inline:
extern inline constexpr int i = 10;
But variables cannot be declared inline in C++11.
Except... when they don't need to be declared inline because the effect has already been achieved implicitly:
struct S {
static constexpr int i = 10;
};
Now, S::i has external linkage and is usable in constant expressions!
You may not even need to define your own class for this, depending on the constant's type: consider std::integral_constant. You can write
using i = std::integral_constant<int, 10>;
and now i::value will do exactly what you want.
I'd started a bare-metal (Cortex-M) project some years ago. At project setup we decided to use gcc toolchain with C++11 / C++14 etc. enabled and even for using C++ exceptions and rtti.
We are currently using gcc 4.9 from launchpad.net/gcc-arm-embedded (having some issue which prevent us currently to update to a more recent gcc version).
For example, I'd wrote a base class and a derived class like this (see also running example here):
class OutStream {
public:
explicit OutStream() {}
virtual ~OutStream() {}
OutStream& operator << (const char* s) {
write(s, strlen(s));
return *this;
}
virtual void write(const void* buffer, size_t size) = 0;
};
class FixedMemoryStream: public OutStream {
public:
explicit FixedMemoryStream(void* memBuffer, size_t memBufferSize): memBuffer(memBuffer), memBufferSize(memBufferSize) {}
virtual ~FixedMemoryStream() {}
const void* getBuffer() const { return memBuffer; }
size_t getBufferSize() const { return memBufferSize; }
const char* getText() const { return reinterpret_cast<const char*>(memBuffer); } ///< returns content as zero terminated C-string
size_t getSize() const { return index; } ///< number of bytes really written to the buffer (max = buffersize-1)
bool isOverflow() const { return overflow; }
virtual void write(const void* buffer, size_t size) override { /* ... */ }
private:
void* memBuffer = nullptr; ///< buffer
size_t memBufferSize = 0; ///< buffer size
size_t index = 0; ///< current write index
bool overflow = false; ///< flag if we are overflown
};
So that the customers of my class are now able to use e.g.:
char buffer[10];
FixedMemoryStream ms1(buffer, sizeof(buffer));
ms1 << "Hello World";
Now I'd want to make the usage of the class a bit more comfortable and introduced the following template:
template<size_t bufferSize> class FixedMemoryStreamWithBuffer: public FixedMemoryStream {
public:
explicit FixedMemoryStreamWithBuffer(): FixedMemoryStream(buffer, bufferSize) {}
private:
uint8_t buffer[bufferSize];
};
And from now, my customers can write:
FixedMemoryStreamWithBuffer<10> ms2;
ms2 << "Hello World";
But from now, I'd observed increasing size of my executable binary. It seems that gcc added symbol information for each different template instantiation of FixedMemoryStreamWithBuffer (because we are using rtti for some reason).
Might there be a way to get rid of symbol information only for some specific classes / templates / template instantiations?
It's ok to get a non portable gcc only solution for this.
For some reason we decided to prefer templates instead of preprocessor macros, I want to avoid a preprocessor solution.
First of all, keep in mind that compiler also generates separate v-table (as well as RTTI information) for every FixedMemoryStreamWithBuffer<> type instance, as well as every class in the inheritance chain.
In order to resolve the problem I'd recommend using containment instead of inheritance with some conversion function and/or operator inside:
template<size_t bufferSize>
class FixedMemoryStreamWithBuffer
{
uint8_t buffer[bufferSize];
FixedMemoryStream m_stream;
public:
explicit FixedMemoryStreamWithBuffer() : m_stream(m_buffer, bufferSize) {}
operator FixedMemoryStream&() { return m_stream; }
FixedMemoryStream& toStream() { return m_stream; }
};
Yes, there's a way to bring the necessary symbols almost down to 0: using the standard library. Your OutStream class is a simplified version of std::basic_ostream. Your OutStream::write is really just std::basic_ostream::write and so on. Take a look at it here. Overflow is handled really closely, though, for completeness' sake, it also deals with underflow i.e. the need for data retrieval; you may leave it as undefined (it's virtual too).
Similarly, your FixedMemoryStream is std::basic_streambuf<T> with a fixed-size (a std::array<T>) get/put area.
So, just make your classes inherit from the standard ones and you'll cut off on binary size since you're reusing already declared symbols.
Now, regarding template<size_t bufferSize> class FixedMemoryStreamWithBuffer. This class is very similar to std::array<std::uint8_t, bufferSize> as for the way memory is specified and acquired. You can't optimize much about that: each instantiation is a different type with all what that implies. The compiler cannot "merge" or do anything magic about them: each instantiation must have its own type.
So either fall back on std::vector or have some fixed-size specialized chunks, like 32, 128 etc. and for any values in between would choose the right one; this can be achieved entirely at compile-time, so no runtime cost.
I get the warning " cast increases required alignment of target type" while compiling the following code for ARM.
char data[2] = "aa";
int *ptr = (int *)(data);
I understand that the alignment requirement for char is 1 byte and that of int is 4 bytes and hence the warning.
I tried to change the alignment of char by using the aligned attribute.
char data[2] __attribute__((aligned (4)));
memcpy(data, "aa", 2);
int *ptr = (int *)(data);
But the warning doesn't go away.
My questions are
Why doesn't the warning go away?
As ARM generates hardware exception for misaligned accesses, I want to make sure that alignment issues don't occur. Is there any other way to write this code so that the alignment issue won't arise?
By the way, when I print alignof(data), it prints 4 which means the alignment of data is changed.
I'm using gcc version 4.4.1. Is it possible that the gcc would give the warning even if the aligned was changed using aligned attribute?
I don't quite understand why you would want to do this... but the problem is that the string literal "aa" isn't stored at an aligned address. The compiler likely optimized away the variable data entirely, and therefore only sees the code as int* ptr = (int*)"aa"; and then give the misalignment warning. No amount of fiddling with the data variable will change how the literal "aa" is aligned.
To avoid the literal being allocated on a misaligned address, you would have to tweak around with how string literals are stored in the compiler settings, which is probably not a very good idea.
Also note that it doesn't make sense to have a pointer to non-constant data pointing at a string literal.
So your code is nonsense. If you still for reasons unknown insist of having an int pointer to a string literal, I'd do some kind of work-around, for example like this:
typedef union
{
char arr[3];
int dummy;
} data_t;
const data_t my_literal = { .arr="aa" };
const int* strange_pointer = (const int*)&my_literal;