Мусор, который создает VC++ 2002

Тема в разделе "WASM.BEGINNERS", создана пользователем Sharp, 7 ноя 2005.

  1. Sharp

    Sharp New Member

    Публикаций:
    0
    Регистрация:
    1 авг 2003
    Сообщения:
    143
    Адрес:
    Ukraine
    При компиляции VC++ 2002 "хелло, ворлда" с "агрессивной оптимизацией" создается ехе-файл размером около 1 КБ:
    Код (Text):
    1. #include <windows.h>
    2.  
    3. #pragma comment(linker,"/MERGE:.rdata=.text")
    4. #pragma comment(linker,"/ALIGN:512")
    5. #pragma comment(linker,"/ENTRY:Main")
    6. #pragma comment(linker,"/NODEFAULTLIB:LIBCMT /NODEFAULTLIB:OLDNAMES")
    7.  
    8. void Main(){
    9.     MessageBox(0, "Hello, world!", "proj", MB_ICONASTERISK);
    10.     ExitProcess(0);
    11. }


    Но стоит только вынести "Hello, world!" в массив:
    Код (Text):
    1. void Main(){
    2.     char buff[128] = "Hello, world!";
    3.     MessageBox(0, buff, "proj", MB_ICONASTERISK);
    4.     ExitProcess(0);
    5. }


    EXEшник увеличивается до 7 с хвостом килобайт, причем добавленный код не похож на CRT, импортирует непонятно зачем следующие функции:

    VirtualAlloc

    HeapFree

    QueryPerformanceCounter

    GetTickCount

    GetCurrentThreadId

    GetCurrentProcessId

    GetSystemTimeAsFileTime

    RtlUnwind

    HeapReAlloc

    HeapAlloc

    Что делает этот код, чем объясняется подобное поведение компилятора и как избежать его включения?



    Кроме того, если вместо #pragma comment(linker,"/NODEFAULTLIB:LIBCMT /NODEFAULTLIB:OLDNAMES") использовать просто #pragma comment(linker,"/NODEFAULTLIB") , компилятор ругается на error LNK2019: unresolved external symbol ___security_cookie referenced in function "void __cdecl Main(void)" (?Main@@YAXXZ)

    Что такое security cookie в данном случае и зачем он нужен?
     
  2. SDragon

    SDragon New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2005
    Сообщения:
    133
    Адрес:
    Siberia
    Должно быть, включена проверка переполнения буфера (/GS). Также советую отключить отладочную информацию в свойствах линкера, включить string pooling (/GF) и объединение секций (/MERGE:".rdata=.text").



    Кстати, если вынести "Hello, world" в локальную переменную-массив, то генерируется ненужный код для копирования строки, заполнения буфера нулями (rep stosd) и выделения памяти на стеке. Лучше вынести в глобальную переменную, причем сделать ее константой:
    Код (Text):
    1. const char buff[128] = "Hello, world!";
    2. void Main() {
    3. MessageBox(0, buff, "proj", MB_ICONASTERISK);
    4. ExitProcess(0);
    5. }
    [​IMG] _700290280__testw.rar
     
  3. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Зачем глобальная переменная?
    Код (Text):
    1.  
    2. void Main(){
    3.     [b]static[/b] char buff[] = "Hello, world!";
    4.     // char * buff = "Hello, world!";
    5.     MessageBox(0, buff, "proj", MB_ICONASTERISK);
    6.     ExitProcess(0);
    7. }


    ___security_cookie отключается /GS-
     
  4. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    #pragma comment(linker, "/ENTRY:start")

    void start()

    {

    }



    или



    __declspec(naked) void start(void)

    {

    }

    и не нужно рантайм отключать, просто не нужно использовать стандартные С'шные функции и исключения
     
  5. SDragon

    SDragon New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2005
    Сообщения:
    133
    Адрес:
    Siberia


    Со static получается 1,5 Кб, а не 1 Кб, т.к. неконстантные переменные (господи, тавтология-то какая! :) помещаются в отдельную секцию .data, а константы идут в ту же .text, что и код. Нужно делать static const:
    Код (Text):
    1. void Main(){
    2.     static const char buff[] = "Hello, world!";
    3.     MessageBox(0, buff, "proj", MB_ICONASTERISK);
    4.     ExitProcess(0);
    5. }


    Asterix: А по-моему, лучше /ENTRY:start указывать в опциях линкера для Release-версии (см. файл выше). Тогда и отладочная версия будет работать, и можно будет без переделки перекомпилировать исходник другим компилятором, например, MinGW.
     
  6. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine




    чревато



    ноля в конце не будет.



    const char * buff= "Hello, world!";



    так лучше будет

    IMHO
     
  7. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Будет там ноль.

    Даже
    Код (Text):
    1. static const char buff[13] = "Hello, world!";
    ни один соответствующий стандарту компилятор не пропустит.
     
  8. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    А вот ещё один прибабах от vc++ (на этот раз vc 7.0):


    Код (Text):
    1. //==================================================================== ==
    2. static int* alloc( int dwSize ){
    3.     return (int*) VirtualAlloc( NULL, dwSize, MEM_COMMIT, PAGE_READWRITE );
    4. }
    5.  
    6. //==================================================================== ==
    7. static void free( int* lpArray, int dwSize ){
    8.     VirtualFree ( (LPVOID) lpArray, dwSize, MEM_DECOMMIT );
    9. }
    10.  
    11. //==================================================================== ==
    12. static int nrandom (int base){
    13.     int        x;
    14.     _asm
    15.     {
    16.         mov eax, nrandom_seed
    17.  
    18.         test eax, 80000000h
    19.         jz  _F
    20.         add eax, 7fffffffh
    21.       _F:  
    22.         xor edx, edx
    23.         mov ecx, 127773
    24.         div ecx
    25.         mov ecx, eax
    26.         mov eax, 16807
    27.         mul edx
    28.         mov edx, ecx
    29.         mov ecx, eax
    30.         mov eax, 2836
    31.         mul edx
    32.         sub ecx, eax
    33.         xor edx, edx
    34.         mov eax, ecx
    35.         mov nrandom_seed, ecx
    36.         div base
    37.         mov x, edx
    38.     }
    39.     return x;
    40. }
    41.  
    42. //==================================================================== ==
    43. void main(){
    44.     int*        array;
    45.     int*        temp_array;
    46.  
    47.     array = alloc( size*4 );
    48.     temp_array = alloc( temp_size*4 );
    49.  
    50.     for ( int i=0; i<temp_size; i++ )
    51.         temp_array[i]=nrandom(i);
    52.  
    53.     .......
    54.     .......
    55.  
    56.     free(array, size);
    57.     free(temp_array, temp_size);
    58.        
    59.     return;
    60. }
    61.  




    При компиляции с /Ox компилятор с умным видом инлайнит ф-ций alloc, free, nrandom. Вроде всё правильно - ф-ции небольшие, требуется скорость - но есть одно но: кроме тех мест, где вставлены инлайном, эти ф-ции также попали в ехе отдельными ф-циями за пределами main, хотя они больше нигде не вызываются, только из main. Зачем дублировать код?
     
  9. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Попробуй

    /link /opt:ref
     
  10. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    S_T_A_S_





    и давно ?



    мне помнится что при инициализации массива компилятор ничего не добавляет ,и это правильно по идее.

    но я могу и ошибаться ...
     
  11. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    staier > и давно ?



    C тех пор, как производители компилятора решат не нарушать стандарт:



    8.5.2 Character arrays [dcl.init.string]

    1 A char array (whether plain char, signed char, or unsigned char) can be initialized by a stringliteral

    (optionally enclosed in braces); a wchar_t array can be initialized by a wide string-literal (optionally

    enclosed in braces); successive characters of the string-literal initialize the members of the array.

    [Example:
    Код (Text):
    1. char msg[] = "Syntax error on line %s\n";
    shows a character array whose members are initialized with a string-literal. Note that because ’\n’ is a

    single character and because a trailing ’\0’ is appended, sizeof(msg) is 25. ]

    2 There shall not be more initializers than there are array elements. [Example:
    Код (Text):
    1. char cv[4] = "asdf"; // error
    is ill-formed since there is no space for the implied trailing ’\0’. ]





    staier > мне помнится что при инициализации массива компилятор ничего не добавляет, и это правильно по идее.



    Компилятор _ничего_ не добавляет, а инициализирует тем, чем просят.

    hint: try sizeof("Hello, world!")



    Можно же и так инициализировать:
    Код (Text):
    1. static const char buff[] = 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!';
     
  12. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    S_T_A_S_



    Ничего не дает. По прежнему два тела функции.
     
  13. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Понял в чём дело - надо /Gy давать ключик.

    Или static поменять на __inline.
     
  14. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    То, что ключами и инлайнами можно добиться я знаю. Дело то не в этом - почему присутствует функция, которая не вызывается??

    Если сделать функцию, которая вообще не вызывается из исходника, то он её не включит в ехе. А если он проинлайнил, то сунет два раза :) Где логика?
     
  15. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    мне кажется на самом деле логика есть

    компилятору по фиг есть в этом obj main или нет , это линкеру интересно.

    линкуется весь obj, вот если ты вынесешьв отдельный файл эти функции , то может и не прилинкует их в не inline



    теоретически это можно отследить , но насколько я знаю , smartlinking только в delphi есть
     
  16. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    cresta > Где логика?



    Логика такая - без /Gy компилятор пихает все функции из исходного файла в объектник одним куском, линкер этот один кусок далее пихает в экзешник, выкидывать какой-то код он не имеет права.

    С ключём /Gy объектник содержит "отдельно" скомпилированные ф-ции, поэтому линкер уже может выкидывать неиспользуемое.
     
  17. like_a

    like_a New Member

    Публикаций:
    0
    Регистрация:
    13 дек 2006
    Сообщения:
    16
    А есть ли ключ подобный /Gy для ml ?