C externs, что псевдоним того же адреса? - PullRequest
2 голосов
/ 06 апреля 2011

Может ли компилятор C предположить, что два разных внешних глобала не могут * иметь псевдоним для одного и того же адреса?

В моем случае у меня есть такая ситуация:

extern int array_of_int[], array_end;

void some_func(void)
{
    int *t;
    for (t = &array_of_int[0]; t != &array_end; t++)
    {
    ...

Полученный двоичный файл, скомпилированный с включенной оптимизацией, не проверяет условие

t != &array_end
перед входом в цикл.Оптимизация компилятора заключается в том, что цикл должен выполняться хотя бы один раз, поскольку t не может сразу равняться &array_end с самого начала.

Конечно, мы нашли это сложным способом.По-видимому, некоторые хакеры ассемблера с секциями компоновщика привели к тому, что два внешних объекта имеют один и тот же адрес.

Спасибо за любой совет!

Ответы [ 4 ]

6 голосов
/ 06 апреля 2011

Короче говоря, да, это предположение свободно.В extern переменных нет ничего особенного.Две переменные не могут быть псевдонимами друг друга.(Если бы ответ был другим, подумайте о хаосе, который может последовать. extern int a, b мог бы создать псевдоним друг друга, что сделало бы семантику любого кода, использующего эти переменные, абсолютно безумной!)

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

1 голос
/ 06 апреля 2011

C99 говорит в 6.2.2 «Строки идентификаторов»:

Идентификатор, объявленный в разных областях или в одной и той же области более одного раза, может быть сделан для ссылки на один и тот же объект или функциюс помощью процесса, называемого связью.(Сноска 21)

...

Сноска 21: Нет связи между различными идентификаторами.

Так что, к сожалению, этот довольно распространенный трюк на ассемблере (которыйЯ использовал ...) не очень хорошо определен.Было бы лучше, чтобы ваш модуль сборки определил array_end как фактический указатель на то, что асм-код загружается с адресом конца массива.Таким образом, код C может быть четко определен, поскольку указатель array_end будет отдельным объектом.

0 голосов
/ 05 июня 2013

Это очень просто в случае, если мы делаем это в коде руки - у нас есть атрибут для этого ..

#include <stdio.h>
int oldname = 1;
extern int newname __attribute__((alias("oldname"))); // declaration
void foo(void)
{
    printf("newname = %d\n", newname); // prints 1
}

и здесь достаточно только extern. Импортировать его в другие файлы - это без проблем. для файла сборки - вы можете использовать команду IMPORT, и у вас есть псевдоним там. :)

0 голосов
/ 06 апреля 2011

Я думаю вот фиксированный код

#include <stdio.h>

extern int array_of_int[];
extern int *array_end;


int main()
{
    int *t;
    for (t = &array_of_int[0]; t != array_end; t++)
    {
        printf("%i\n", *t);
    }
    return 0;
}

в другом модуле компиляции:

int array_of_int[] = { }; // { 1,2,3,4 };
int *array_end = array_of_int + (sizeof(array_of_int)/sizeof(array_of_int[0]));

Он компилируется в это (-O3, gcc 4.4.5 i686)

080483f0 <main>:
 80483f0:       55                      push   %ebp
 80483f1:       89 e5                   mov    %esp,%ebp
 80483f3:       83 e4 f0                and    $0xfffffff0,%esp
 80483f6:       53                      push   %ebx
 80483f7:       83 ec 1c                sub    $0x1c,%esp
 80483fa:       81 3d 24 a0 04 08 14    cmpl   $0x804a014,0x804a024
 8048401:       a0 04 08 
 8048404:       74 2f                   je     8048435 <main+0x45>
 8048406:       bb 14 a0 04 08          mov    $0x804a014,%ebx
 804840b:       90                      nop
 804840c:       8d 74 26 00             lea    0x0(%esi,%eiz,1),%esi
 8048410:       8b 03                   mov    (%ebx),%eax
 8048412:       83 c3 04                add    $0x4,%ebx
 8048415:       c7 44 24 04 00 85 04    movl   $0x8048500,0x4(%esp)
 804841c:       08 
 804841d:       c7 04 24 01 00 00 00    movl   $0x1,(%esp)
 8048424:       89 44 24 08             mov    %eax,0x8(%esp)
 8048428:       e8 d7 fe ff ff          call   8048304 <__printf_chk@plt>
 804842d:       39 1d 24 a0 04 08       cmp    %ebx,0x804a024
 8048433:       75 db                   jne    8048410 <main+0x20>
 8048435:       83 c4 1c                add    $0x1c,%esp
 8048438:       31 c0                   xor    %eax,%eax
 804843a:       5b                      pop    %ebx
 804843b:       89 ec                   mov    %ebp,%esp
 804843d:       5d                      pop    %ebp
 804843e:       c3                      ret    
 804843f:       90                      nop
...