Jump to content

    
Sign in to follow this  
vinni-puch

Снова о gcc и невыровненном доступе к памяти

Recommended Posts

Так понятней?

Да все было и так понятно! Не понятно зачем городить этот огород, не проще ли взять современный компилятор и объяснить ему что, где и в каком порядке лежит! Тогда код будет и понятнее и оптимальнее ;) потому что есть инструкции чтения с переворотом и т.п.

 

 

Share this post


Link to post
Share on other sites
Да все было и так понятно! Не понятно зачем городить этот огород, не проще ли взять современный компилятор и объяснить ему что, где и в каком порядке лежит! Тогда код будет и понятнее и оптимальнее ;) потому что есть инструкции чтения с переворотом и т.п.

Прошу в студию код, как "правильно" объявить структуру blabla у ТС для gcc.

 

KRS все уже объяснил, почему делать так, как Вы сделали, неразумно.

Только что проверил.

     uint8_t msg[]  __attribute__ ((aligned (16))) =
        { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A };

    struct blabla_t {
        char ch;
        int that __attribute__((packed));
    } __attribute__((packed));
    
    struct blabla_t *bla;

    int a;

    bla=&msg[3];
    a = bla->that;
    printf("a = 0x%08X\n", a);

    bla=&msg[0];
    a = bla->that;
    printf("a = 0x%08X\n", a);

 

результат:

 

a = 0x08070605
Ошибка шины

 

Итог: никакие "#pragma packed" вам не помогут!

Вот теперь понятно?

 

P.S.

Я включил в системе контроль alignment.

"Ошибка шины" это "SIGBUS" - и есть ошибка невыровненного доступа.

Share this post


Link to post
Share on other sites
Итог: никакие "#pragma packed" вам не помогут!

Вот теперь понятно?

Ну вам не помогают, а мне помогают

 

#include <stdint.h>
#include <stdio.h>

#pragma pack(1)
typedef struct {
    char ch;
    int that;
} blabla_t;
#pragma pack()

void test(blabla_t *bla)
{
    printf("a = 0x%08X\n", bla->that);
}

uint8_t msg[]  __attribute__ ((aligned (16))) =
        { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A };
void test2(void)
{
    blabla_t *bla;

    int a;

    bla= (blabla_t *)&msg[3];
    a = bla->that;
    printf("a = 0x%08X\n", a);

    bla=(blabla_t *)&msg[0];
    a = bla->that;
    printf("a = 0x%08X\n", a);
}

 

По листингу все читается по байтам, так что все ок!

Все таки надо использовать typedef и при присваивании преобразовывать указатели, что бы не плодить warningи, на которые стоит обращать внимание!

 

 

Share this post


Link to post
Share on other sites
Ну вам не помогают, а мне помогают

....

По листингу все читается по байтам, так что все ок!

Все таки надо использовать typedef и при присваивании преобразовывать указатели, что бы не плодить warningи, на которые стоит обращать внимание!

Давайте разбираться:

Собрал ваш код gcc (4.5.2, "-O0"). Ошибка доступа ЕСТЬ!

objdump -d -S ./a.out

 

Вывод:

080483e3 <test2>:

uint8_t msg[]  __attribute__ ((aligned (16))) =
        { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A };

void test2(void)
{
80483e3:    55                       push   %ebp
80483e4:    89 e5                    mov    %esp,%ebp
80483e6:    83 ec 28                 sub    $0x28,%esp
    blabla_t *bla;

    int a;

    bla= (blabla_t *)&msg[3];
80483e9:    b8 20 a0 04 08           mov    $0x804a020,%eax
80483ee:    83 c0 03                 add    $0x3,%eax
80483f1:    89 45 f4                 mov    %eax,-0xc(%ebp)
    a = bla->that;
80483f4:    8b 45 f4                 mov    -0xc(%ebp),%eax
80483f7:    8b 40 01                 mov    0x1(%eax),%eax
80483fa:    89 45 f0                 mov    %eax,-0x10(%ebp)
    printf("a = 0x%08X\n", a);
80483fd:    b8 20 85 04 08           mov    $0x8048520,%eax
8048402:    8b 55 f0                 mov    -0x10(%ebp),%edx
8048405:    89 54 24 04              mov    %edx,0x4(%esp)
8048409:    89 04 24                 mov    %eax,(%esp)
804840c:    e8 e3 fe ff ff           call   80482f4 <printf@plt>

    bla=(blabla_t *)&msg[0];
8048411:    c7 45 f4 20 a0 04 08     movl   $0x804a020,-0xc(%ebp)
    a = bla->that;
8048418:    8b 45 f4                 mov    -0xc(%ebp),%eax
804841b:    8b 40 01                 mov    0x1(%eax),%eax
804841e:    89 45 f0                 mov    %eax,-0x10(%ebp)
    printf("a = 0x%08X\n", a);
8048421:    b8 20 85 04 08           mov    $0x8048520,%eax
8048426:    8b 55 f0                 mov    -0x10(%ebp),%edx
8048429:    89 54 24 04              mov    %edx,0x4(%esp)
804842d:    89 04 24                 mov    %eax,(%esp)
8048430:    e8 bf fe ff ff           call   80482f4 <printf@plt>
}
8048435:    c9                       leave  
8048436:    c3                       ret

И где тут по-байтное обращение?

Share this post


Link to post
Share on other sites
Давайте разбираться:

Собрал ваш код gcc (4.5.2). Ошибка доступа ЕСТЬ!

И при чем здесь ARM?

Интел умеет читать по не выравненному адресу, зачем читать по байтам?

 

 

Share this post


Link to post
Share on other sites
И при чем здесь ARM?

Интел умеет читать по не выравненному адресу, зачем читать по байтам?

Может, но не обязан. (См. eFlags, бит 18)

 

И при чем здесь ARM?

Да, проверил на ARM. Действительно читает по-байтно.

 

P.S. Вот бы ещё ссылку на стандарт какой.

Share this post


Link to post
Share on other sites
P.S. Вот бы ещё ссылку на стандарт какой.

Причем тут стандарт? Что Вы хотите увидеть? Большими красными буквами "Компилятор языка 'C' обязан уметь корректно работать со структурами данных"?

Есть структура данных, Вы полно и корректно описали, что она из себя представляет. Все, любой компилятор обязан правильно работать.

Зачем указывать отдельно, например, в ГОСТ на автомобиль, то, что должен уметь перемещаться и без запряженной лошади? И уж тем более, не стоит ее в автомобиль запрягать,

даже если в ГОСТ на него не написано, что лошадь не требуется.

Share this post


Link to post
Share on other sites
Да, проверил на ARM. Действительно читает по-байтно.

А хороший компилер, в случае с

bla= (blabla_t *)&msg[3];

a = bla->that;

должен читать сразу слово! (при соотв. уровне оптимизации) потому что в данном случае возможно проследить выравнивание. И, например, RVCT так и делает!

 

Share this post


Link to post
Share on other sites

Если компилятор сам расположил структуру в памяти, то вне зависимости от директивы pack он должен корректно обращаться к памяти при доступе к любому полю.

 

А вот если с указателями работать вольно, то запросто можно схлопотать ошибку доступа. Или вот так :)

 

*((int *)0x40000007)=0;

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this