реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Снова о gcc и невыровненном доступе к памяти
vinni-puch
сообщение Jun 28 2011, 07:29
Сообщение #1





Группа: Новичок
Сообщений: 4
Регистрация: 6-05-09
Пользователь №: 48 742



Знаю что такие темы уже были, тем не менее я так и не разобрался как сделать лучше и проще всего
Есть Atmel AT91RM9200, на котором крутится Linux, и на который надо портировать софтинку, в которой есть необходимость обращаться к элементам структуры типа:

struct blabla {
char ch;
int that;
} blabla_t


При обращении к that и происходит, собсно, невыровненный доступ к памяти.
При этом объявить структуру с параметром __attribute__ ((__aligned__(4))), или дополнить паддингом я не могу, ибо по сети приходит пакет, на который собсно и накладывается структура.
Да и отловить все подобные обращения в сотне исходный файлов не представляется оптимальным путём.

Собственно, вопрос, как быть? Неужели нет простой возможности обойти проблему в банальнейшей операции обращения к полю структуры?

И еще одна непонятка. Вроде бы бит A в CP15 включен, однако никаких исключений при таких обращения не происходит. Поэтому я даже не могу узнать о таком обращении. ЧЯДНТ? Может, надо еще что то где то включить? Или в линухе реализована обработка подобного исключения но у меня она почему то не работает?

Всем спасибо!
Go to the top of the page
 
+Quote Post
KRS
сообщение Jun 28 2011, 07:36
Сообщение #2


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(vinni-puch @ Jun 28 2011, 11:29) *
При этом объявить структуру с параметром __attribute__ ((__aligned__(4))), или дополнить паддингом я не могу, ибо по сети приходит пакет, на который собсно и накладывается структура.

Так по умолчанию и будет выравнивание! Его надо для этой структуры отключать. (если конечно у вас не выключено выравнивание везде). Если выравнивание будет выключено компилятор для не выравненных членов будет генерировать побайтовый или пословный доступ!

Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 28 2011, 07:38
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (vinni-puch @ Jun 28 2011, 09:29) *
Знаю что такие темы уже были, тем не менее я так и не разобрался как сделать лучше и проще всего

Лучше и проще всего писать ВНЯТНЫЕ исходники. В этом случае Вы будете правильно поняты компилятором и компилятор выполнит все необходимые дополнительные действия по доступу к элементам такой структуры.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 28 2011, 07:40
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(vinni-puch @ Jun 28 2011, 11:29) *
Или в линухе реализована обработка подобного исключения но у меня она почему то не работает?

У меня на работе стоит компьютер Sparc 64-bit с линуксом. Там логи засыпаны сообщениями о невыравненном доступе к памяти. Виновник - модуль cifs, т.е. часть ядра линукс. Очевидно, ядро перехватывает невыравненные обращения к памяти и прозрачным образом их обрабатывает. Ну а пейсатели модуля cifs, очевидно, не парятся и полагаются на эту фичу ядра.
Мне кажется, у Вас должна быть та же фича.

Update:
Кстати, в исходниках модуля cifs можете и подсмотреть, как они объявляют такие структуры:
cifspdu.h
Go to the top of the page
 
+Quote Post
vinni-puch
сообщение Jun 28 2011, 08:04
Сообщение #5





Группа: Новичок
Сообщений: 4
Регистрация: 6-05-09
Пользователь №: 48 742



Ребят, по факту у меня ЕСТЬ невыровненное обращение, и по умолчанию компилятор ничего не выравнивает. Т. е. типа __attribute__((packed))
Я очень долго искал в чем же бага, потому что у меня не было ни одного сообщения о невыровненности, (опять же, почему их нет?)
потом написал вырожденный случай в 10 строк, который работает неправильно - именно из-за невыровненности.

Так вот вопрос в этом и состоит, что как и где сказать компилятору, что обращения к этой структуре будут невыровненны. так чтобы внести минимальное кол-во исправлений в код. Но не пользуясь атрибутом aligned, потому что это изменяет физический размер структуры, а я привязан к формату кадра.
Или как заставить линукс эти невыровненные обращения подменять сложными чтениями/сдвигами, чтобы для меня это вообще прозрачно было. Ведь не валится ничего!
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 28 2011, 08:11
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(vinni-puch @ Jun 28 2011, 12:04) *
Ребят, по факту у меня ЕСТЬ невыровненное обращение, и по умолчанию компилятор ничего не выравнивает. Т. е. типа __attribute__((packed))

Откуда инфа? Может быть, Вам показалось?

Цитата(vinni-puch @ Jun 28 2011, 12:04) *
Я очень долго искал в чем же бага, потому что у меня не было ни одного сообщения о невыровненности, (опять же, почему их нет?)
потом написал вырожденный случай в 10 строк, который работает неправильно - именно из-за невыровненности.

Опять же, может Вам показалось? Напишите подробнее.

Цитата(vinni-puch @ Jun 28 2011, 12:04) *
Так вот вопрос в этом и состоит, что как и где сказать компилятору, что обращения к этой структуре будут невыровненны. так чтобы внести минимальное кол-во исправлений в код. Но не пользуясь атрибутом aligned, потому что это изменяет физический размер структуры, а я привязан к формату кадра.

Неприлично не читать ответы на вопросы. См. выше: содержимое файла cifspdu.h.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 28 2011, 08:21
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (vinni-puch @ Jun 28 2011, 10:04) *
Так вот вопрос в этом и состоит, что как и где сказать компилятору, что обращения к этой структуре будут невыровненны.

Ничего, кроме информации о том, что он работает невыровненной структурой. В Вашем случае Вам удалось написать нечто невнятное, например, с преобразованиями типов и указателей, и компилятор НЕ получил эту информацию.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Petka
сообщение Jun 28 2011, 08:58
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886



Цитата(vinni-puch @ Jun 28 2011, 11:29) *
Код
struct blabla {
    char ch;
    int that;
} blabla_t

При обращении к that и происходит, собсно, невыровненный доступ к памяти.

Не верю!
либо вы делаете примерно так:
Код
char *incomming_message;
.....
struct blabla *b;
b = (struct blabla *) incomming_message; /* Так делать нельзя, т.к. компилятор не может ничего узнать будет ли то, куда указывает incomming_message выровнено в памяти! */

b->that = 100500; /* Если incomming_message не было выровнено, то и на доступ внутри структуры тоже будет ошибка выравнивания */


Один из вариантов решения (ИМХО не лучший):

Код
char *incomming_message;
.....
struct blabla b;

memcpy(&b, incomming_message); /* Таким образом мы создаём копию данных, которые гарантированно выровнены в памяти */

b.that = 100500; /* В этом месте компилятор обязан сгенерировать код без невыровненных обращений */

ИМХО более надёжный путь декодировать данные, приходящие с внешних каналов, не наступая на грабли (aligned/BigEndian):
Код
int read_u8(uint8_t **message, size_t *len, uint8_t *retval){
    if (*len >= sizeof(uint8_t) ){
        *retval = **message;
        *message += sizeof(uint8_t);
        *len -= sizeof(uint8_t);
        return 0;  /* Ok */
    }
    return (-1);    /* Fail */
}

int read_u16_LE(uint8_t **message, size_t *len, uint16_t *retval){
    uint8_t msb;
    uint8_t lsb;
    if(read_u8(message, len, &lsb) < 0){
        return (-1);  /* Fail */
    }

    if(read_u8(message, len, &msb) < 0){
        return (-1);  /* Fail */
    }

    *retval = (msb << 8) | lsb;

    return (0);  /* Ok */
}

int read_u16_BE(uint8_t **message, size_t *len, uint16_t *retval){
    uint8_t msb;
    uint8_t lsb;
    if(read_u8(message, len, &msb) < 0){
        return (-1);  /* Fail */
    }

    if(read_u8(message, len, &lsb) < 0){
        return (-1);  /* Fail */
    }

    *retval = (msb << 8) | lsb;

    return (0);  /* Ok */
}


как-то так =)
Go to the top of the page
 
+Quote Post
vinni-puch
сообщение Jun 28 2011, 09:04
Сообщение #9





Группа: Новичок
Сообщений: 4
Регистрация: 6-05-09
Пользователь №: 48 742



Цитата(scifi @ Jun 28 2011, 11:11) *
Неприлично не читать ответы на вопросы. См. выше: содержимое файла cifspdu.h.

Было бы неприлично, если бы не читал. Ан нет sm.gif Вы же сами сказали что у вас валятся ошибки этого модуля. Т.е. он заведомо написан неверно. Я посмотрел, там действительно все структуры объявляются с атрбиутом packed. НО этот атрибут делает заведомо наоборот от того что мне нужно, поэтому там все так и работает.

В качестве док-ва прилагаю тестовую програмку и ЛОГ, в котором видно что работает она неправильно, можете сравнить ее вывод с тем, что даст вам хостовый компутер. Видно так же, почему мне не подходят все эти манипуляции с атрибутами структуры
К сожалению загружать файлы мне запрещено, вставляю в тело

И, отвечая частично на свой вопрос - сообщения не вываливались, потому что есть такой файл как /proc/cpu/alignment, По дефолту ничего не делается. Если записать туда 1 - будет лог. Если 2 - то будет фиксить. В логе видно, что это действительно работает.

Програмка:
CODE

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

typedef struct bpdu_body_y {
unsigned char flags;
unsigned char root_id[8];
unsigned char root_path_cost[4];
unsigned char bridge_id[8];
unsigned char port_id[2];
unsigned char message_age[2];
unsigned char max_age[2];
unsigned char hello_time[2];
unsigned char forward_delay[2];
} BPDU_BODY_Y;

typedef struct bpdu_body_t {
unsigned char flags;
unsigned char root_id[8];
unsigned char root_path_cost[4] __attribute__ ((__aligned__(4)));
unsigned char bridge_id[8];
unsigned char port_id[2];
unsigned char message_age[2];
unsigned char max_age[2];
unsigned char hello_time[2];
unsigned char forward_delay[2];
} __attribute__ ((__aligned__(4))) BPDU_BODY_T;

int main(int argc, char *argv[])
{
int i;
volatile char *memo;
volatile u32 *imemo;
BPDU_BODY_T *bmemo;
BPDU_BODY_Y *ymemo;

printf ("sizeof unaligned struct = %d; sizeof aligned struct = %d\n", sizeof(BPDU_BODY_Y), sizeof(BPDU_BODY_T));

memo = (char *)malloc(sizeof (BPDU_BODY_T));

for (i = 0; i < sizeof (BPDU_BODY_T); i++) {
memo[i] = i;
}

printf ("------------------------------------------------------------------------------------------------------\n\t");
bmemo = memo;
ymemo = memo;
printf ("\tMemory contents: \n\n");
for (i = 0; i < sizeof(BPDU_BODY_T); i++) {
printf("%02X", memo[i]);
if (!((i+1)%4)) {
printf ("|");
}
}
printf ("\n----------------------------------------------------------------\n");
printf ("It should be %02X%02X%02X%02X\n\n",
ymemo->root_path_cost[3], ymemo->root_path_cost[2],
ymemo->root_path_cost[1], ymemo->root_path_cost[0]);
memo = memo + 9;
printf ("Addr of unaligned root_path_cost is %p; Addr of aligned root_path_cost is %p; \n",
&ymemo->root_path_cost, &bmemo->root_path_cost);
printf("\tUnaligned root_path_cost %08X\n\t", *((int *)(ymemo->root_path_cost)));
printf("Aligned root_path_cost %08X\n", *((int *)(bmemo->root_path_cost)));

return 0;
}


ЛОГ:
CODE

root@OpenWrt:/# tst1
sizeof unaligned struct = 31; sizeof aligned struct = 36
------------------------------------------------------------------------------------------------------
Memory contents:

00010203|04050607|08090A0B|0C0D0E0F|10111213|14151617|18191A1B|1C1D1E1F|20212223
|
----------------------------------------------------------------
It should be 0C0B0A09

Addr of unaligned root_path_cost is 0x11011; Addr of aligned root_path_cost is 0x11014;
Unaligned root_path_cost 080B0A09
Aligned root_path_cost 0F0E0D0C
root@OpenWrt:/# echo 2 > /proc/cpu/alignment
root@OpenWrt:/# tst1
sizeof unaligned struct = 31; sizeof aligned struct = 36
------------------------------------------------------------------------------------------------------
Memory contents:

00010203|04050607|08090A0B|0C0D0E0F|10111213|14151617|18191A1B|1C1D1E1F|20212223
|
----------------------------------------------------------------
It should be 0C0B0A09

Addr of unaligned root_path_cost is 0x11011; Addr of aligned root_path_cost is 0x11014;
Unaligned root_path_cost 0C0B0A09
Aligned root_path_cost 0F0E0D0C

Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 28 2011, 09:27
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(vinni-puch @ Jun 28 2011, 13:04) *
Вы же сами сказали что у вас валятся ошибки этого модуля. Т.е. он заведомо написан неверно.

Срочно сообщите Линусу! Пусть пофиксит :-)
А если серьёзно, то не вижу проблемы в том, чтобы полагаться на линуксовый обработчик невыравненного доступа. Можете называть это предупреждениями, а не ошибками.

Цитата(vinni-puch @ Jun 28 2011, 13:04) *
В качестве док-ва прилагаю тестовую програмку и ЛОГ, в котором видно что работает она неправильно, можете сравнить ее вывод с тем, что даст вам хостовый компутер. Видно так же, почему мне не подходят все эти манипуляции с атрибутами структуры

Многабукаф. Ниасилил.
Go to the top of the page
 
+Quote Post
KRS
сообщение Jun 28 2011, 10:01
Сообщение #11


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(Petka @ Jun 28 2011, 12:58) *
Код
char *incomming_message;
.....
struct blabla *b;
b = (struct blabla *) incomming_message; /* Так делать нельзя, т.к. компилятор не может ничего узнать будет ли то, куда указывает incomming_message выровнено в памяти! */

Зато можно сделать typedef с опцией packed, тогда все будет ок! и код будет понятный.
Go to the top of the page
 
+Quote Post
Petka
сообщение Jun 28 2011, 10:45
Сообщение #12


Профессионал
*****

Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886



Цитата(KRS @ Jun 28 2011, 14:01) *
Зато можно сделать typedef с опцией packed, тогда все будет ок! и код будет понятный.

1) И чем это поможет?
2) Всяческие атрибуты выходят за стандарт Си. Когда однажды потом откомпилируете свой код с подобными атрибутами другим компилятором (или под другую архитектуру). Или даже если в рамках одной архитектуры и компилятора будет изменена endianness, то результат будет непредсказуемым.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 28 2011, 12:01
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (vinni-puch @ Jun 28 2011, 11:04) *
Програмка:

Не сочли нужным объявить, что структура BPDU_BODY_Y пакованная. Что написали, то и получили.


QUOTE (Petka @ Jun 28 2011, 10:58) *
как-то так =)

Совершенно дикие действия sad.gif с трудноуловимым смыслом sad.gif.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
KRS
сообщение Jun 28 2011, 13:42
Сообщение #14


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(Petka @ Jun 28 2011, 14:45) *
2) Всяческие атрибуты выходят за стандарт Си. Когда однажды потом откомпилируете свой код с подобными атрибутами другим компилятором (или под другую архитектуру). Или даже если в рамках одной архитектуры и компилятора будет изменена endianness, то результат будет непредсказуемым.

Ну #pragma pack уже практически стандартно поддерживается всеми компилерами и GCC в том числе.
endianness тоже можно указать для структуры.
А при помощи С99 и #define _Pragma() можно сделать правильное определение структуры для всех адекватных компиляторов!

Go to the top of the page
 
+Quote Post
Petka
сообщение Jun 28 2011, 13:46
Сообщение #15


Профессионал
*****

Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886



Цитата(zltigo @ Jun 28 2011, 16:01) *
Совершенно дикие действия sad.gif с трудноуловимым смыслом sad.gif.

Что в них "дикого"?
Если смысл непонятен, поясню:
Если информационный пакет пришёл по "сети" или из другого источника, когда не гарантируется что данные будут располагаться в памяти выровнено или когда Endianness отсылающей стороны может не совпасть с получателем. Тогда есть только одна возможность считывать поля структуры из памяти - побайтно, а потом собирать байты в слова. Описанный выше механизм позволяет из произвольно расположенной структуры в памяти вычитывать последовательно с гарантированно одинаковым результатом независимо от архитектуры, компиляторов и всяческих выравниваний.
Разумеется, когда структура заполняется и пересылается в рамках одного вычислителя, то этот метод избыточен.
Так понятней?
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 20:13
Рейтинг@Mail.ru


Страница сгенерированна за 0.01508 секунд с 7
ELECTRONIX ©2004-2016