Переключение на Главную Страницу Страницы: [1] 2 3  ОтправитьПечать
Очень популярная тема (более 25 ответов) declspec(__dllimport) и операция взятия адреса (число прочтений - 15380 )
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
declspec(__dllimport) и операция взятия адреса
17. Мая 2008 :: 23:57
Печать  
Веселенькая тема.

Начало здесь: http://www.1cpp.ru/forum/YaBB.pl?num=1204706900/152#152

Теперь берем icpp от 2008-05-17 и смотрим CSerializeToString::Setup() - да, там пока еще есть SetTrapOnImportFunc.
Смотрим CValue - да нет, все ок, - объявлено как declspeс(__dllimport).
Так какого х"" мы получаем адрес переходника, а не функции?

Не придумав ничего лучше, я делаю вывод: управлять типом получаемого адреса для импортируемой функции в С++ невозможно.
Если я не прав - велкам ту дискасс.

P.S.
Не из праздного интереса тема эта.
Данная хе""я чисто компилятро-зависима и при переходе на VS8/VS9 начинает вести себя по-разному. Улыбка
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: declspec(__dllimport) и операция взятия адреса
Ответ #1 - 18. Мая 2008 :: 00:07
Печать  
А что ты хочешь? Улыбка Нестандартизованный функционал - работает, как захочет левая нога реализатора. Это к пользе стандартов.

Значит, нужно писать так, чтобы не зависеть от такой детали реализации. Я так понимаю, проблемы только при охучивании этих функций? Значит, выхода, похоже, два: GetProcAddress или модификация таблиц импорта всех загруженных модулей 1С.
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: declspec(__dllimport) и операция взятия адреса
Ответ #2 - 18. Мая 2008 :: 00:32
Печать  
Да, это я понимаю.
Это крик души был о тщетности сущего - надо ж тебя было хоть чем-то порадовать. Улыбка

В документации к VS9, кстати, этот момент нормально документирован (в msdn oct 2005 - еще нет):
Цитата:
The following code example shows how to use _declspec(dllimport) to import function calls from a DLL into an application. Assume that func1 is a function that resides in a DLL separate from the .exe file that contains the main function.

Without __declspec(dllimport), given this code:

int main(void)
{
   func1();
}


the compiler generates code that looks like this:

call func1


and the linker translates the call into something like this:

call 0x4000000         ; The address of 'func1'.


If func1 exists in another DLL, the linker cannot resolve this directly because it has no way of knowing what the address of func1 is. In 16-bit environments, the linker adds this code address to a list in the .exe file that the loader would patch at run time with the correct address. In 32-bit and 64-bit environments, the linker generates a thunk of which it does know the address. In a 32-bit environment the thunk looks like:

0x40000000:    jmp DWORD PTR __imp_func1


Here imp_func1 is the address for the func1 slot in the import address table of the .exe file. All the addresses are thus known to the linker. The loader only has to update the .exe file's import address table at load time for everything to work correctly.

Therefore, using __declspec(dllimport) is better because the linker does not generate a thunk if it is not required. Thunks make the code larger (on RISC systems, it can be several instructions) and can degrade your cache performance. If you tell the compiler the function is in a DLL, it can generate an indirect call for you.

So now this code:

__declspec(dllimport) void func1(void);
int main(void)
{
   func1();
}


generates this instruction:

call DWORD PTR __imp_func1


There is no thunk and no jmp instruction, so the code is smaller and faster.

On the other hand, for function calls inside a DLL, you do not want to have to use an indirect call. You already know a function's address. Because time and space are required to load and store the address of the function before an indirect call, a direct call is always faster and smaller. You only want to use __declspec(dllimport) when calling DLL functions from outside the DLL itself. Do not use __declspec(dllimport) on functions inside a DLL when building that DLL.


Только ICL 9.1 (что там с 10.1 смотреть уже лениво), похоже, эту документацию не читал.
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: declspec(__dllimport) и операция взятия адреса
Ответ #3 - 18. Мая 2008 :: 00:36
Печать  
kms писал(а) 18. Мая 2008 :: 00:32:
Это крик души был о тщетности сущего - надо ж тебя было хоть чем-то порадовать. Улыбка

Хренасе, радость Улыбка

А ты что, 1С++ на VC переводишь? Улыбка И как, получается?
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: declspec(__dllimport) и операция взятия адреса
Ответ #4 - 18. Мая 2008 :: 00:50
Печать  
Uzhast писал(а) 18. Мая 2008 :: 00:36:
А ты что, 1С++ на VC переводишь? Улыбка И как, получается?

Перевожу.
С Армянского на Ваганьковское. Смех

Получилось.
Вот, думаю, как теперь признаться, что свалить с ICL задумал.

Давай может еще разок завтра подумаем, есть ли смысл оставаться на ICL.
Я, если честно, от его приколов подустал.
От VC6 CRT - тоже.

С VC8/VC9 по логике тоже не все гладко - самое главное - CRT различные с VC6.
По идее, должно вызывать проблемы, но реально пока ни одной не вижу.

Но icpp в релизе на двух ядрах собирается за 12 секунд.
По скорости (тестировал очень кратко индексацию и заполнение в ИТ) - то же самое, что и ICL.

Ну, вот, может быть, ты еще каких-нибудь потенциальных проблем подскажешь.
Уповаю с надеждой. Улыбка
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: declspec(__dllimport) и операция взятия адреса
Ответ #5 - 18. Мая 2008 :: 00:53
Печать  
kms писал(а) 18. Мая 2008 :: 00:50:
С VC8/VC9 по логике тоже не все гладко - самое главное - CRT различные с VC6.
По идее, должно вызывать проблемы, но реально пока ни одной не вижу.

Вот тут надо будет особенно внимательно все проверять. Как проверял совместимость CRT?
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: declspec(__dllimport) и операция взятия адреса
Ответ #6 - 18. Мая 2008 :: 01:03
Печать  
Uzhast писал(а) 18. Мая 2008 :: 00:53:
Вот тут надо будет особенно внимательно все проверять. Как проверял совместимость CRT?

Тесты пока прогнал для icpp - так что считай, что никак.
Надо будет потом нормально озадачиться, исходники crt сравнить.
Надеюсь, конечно, что там new/delete сводится к одному и тому же malloc/free.

Вот, на всякий случай, что пока получилось.
Только это для VS9 - там многоядерная компиляция есть.

Ну, если в sln версию поменять, думаю и на VS8 пойдет
Код
Выбрать все
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
 


Только из-за сабжа при создании ИТ будет падать - потом переделаю Setup().
  

Source_VS9.RAR ( 1146 KB | Загрузки )

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: declspec(__dllimport) и операция взятия адреса
Ответ #7 - 18. Мая 2008 :: 01:29
Печать  
Кстати, помнишь, я как-то тебе уже рассказывал, что однажды собирал Йоксель студийным компилятором и все нормально собиралось (за исключением некоторого кода из 1С++, которого уже нет)? Тогда меня остановили сомнения насчет CRT. Но если тебе удастся выяснить, что с CRT все будет в порядке, то почему бы и не перейти? В 1С++ практически (или даже вообще) нет задач, для которых скорость кода имеет значение (клинические случаи не рассматриваем). Да и Студийный компилятор не такой уж и плохой по скорости полученного кода.
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: declspec(__dllimport) и операция взятия адреса
Ответ #8 - 18. Мая 2008 :: 01:48
Печать  
Да, по скорости все нормально.
А скорость компиляции - вообще песня после ICL.

Даже LTCG работает приемлемое время.
Но icpp/LTCG не удалось заставить работать - причина пока не известна.
Забавно не работает кстати: "СоздатьОбъект("ИндексированнаяТаблица")" говорит что-то типа "неудачная попытка создания", хз почему.

Насчет CRT - может стоит сосредоточиться на корректной работе с памятью c учетом границ модулей.
Не знаю, насколько это возможно в текущем icpp.

Ну, namespace std, по идее, должно выпрямиться.
Помнишь - при dynamic_cast мне разная фигня прилетала для non-rtti объектов.

P.S.
В принципе, можно вообще стараться код совместимым с обоими компиляторами делать.
VS, кстати, более строг в отношении ошибок, даже по сравнению с ICL; - это тоже неплохо.
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: declspec(__dllimport) и операция взятия адреса
Ответ #9 - 18. Мая 2008 :: 01:56
Печать  
kms писал(а) 18. Мая 2008 :: 01:48:
Да, по скорости все нормально.
А скорость компиляции - вообще песня после ICL.

Ну, 9-й Интел тоже не так уж сильно тормозит Улыбка

kms писал(а) 18. Мая 2008 :: 01:48:
Забавно не работает кстати: "СоздатьОбъект("ИндексированнаяТаблица")" говорит что-то типа "неудачная попытка создания", хз почему.

Возможно, вылез наружу скрытый баг  Смех Или заглючил ms-specific. В 1С++-ных контекстах оно есть. По стандартам надо код писать Улыбка Йоксель после LTCG нормально работает.

kms писал(а) 18. Мая 2008 :: 01:48:
Насчет CRT - может стоит сосредоточиться на корректной работе с памятью c учетом границ модулей.
Не знаю, насколько это возможно в текущем icpp.

Это, конечно, надо смотреть. Но вроде бы там полно случаев, когда память выделяется в 1С и освобождается в 1С++ и наоборот - тот же CString можно взять.


kms писал(а) 18. Мая 2008 :: 01:48:
В принципе, можно вообще стараться код совместимым с обоими компиляторами делать.

Ну это понятно Улыбка
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: declspec(__dllimport) и операция взятия адреса
Ответ #10 - 18. Мая 2008 :: 02:21
Печать  
Uzhast писал(а) 18. Мая 2008 :: 01:56:
Ну, 9-й Интел тоже не так уж сильно тормозит Улыбка

Ну... да...
Но вообще, release у меня собирается около минуты, а здесь - 12 сек.

Цитата:
Возможно, вылез наружу скрытый баг  Смех Или заглючил ms-specific. В 1С++-ных контекстах оно есть. По стандартам надо код писать Улыбка Йоксель после LTCG нормально работает.

А попробуй Йоксель собрать в VS, соберется? Подмигивание (Я MFC и ATL из PSDK брал, остальное - из VS8 или VS9; STLPort - не брал, boost - брал).
Я, наверно, для LTCG попробую простой какой-нибудь проектик сделать для начала, может что-то прояснится.

Цитата:
Это, конечно, надо смотреть. Но вроде бы там полно случаев, когда память выделяется в 1С и освобождается в 1С++ и наоборот - тот же CString можно взять.

А где такое видел? (правда не помню)

Кстати, я тут подумал - все равно с CDataRow плохо получилось.
Ибо выделяется она поставщиком - а удаляется контролом - неправильный интерфейс.
Надо, видать, самоликвидацию сделать, типа Release(), и заменить мои простые shared_ptr на shared_ptr с ликвидаторами.

---
А, да, посмотрел на new/delete и malloc/calloc/sbheap в VS6/VS9 crt.
Близнецы-братья, только в VS9 оставлены только multithreaded WINHEAP варианты, и некоторые неточности исправлены.
Так что, думаю, все нормально будет, даже с похмелюги и в понедельник. Улыбка
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Uzhast
1c++ power user
Отсутствует



Сообщений: 1341
Зарегистрирован: 30. Августа 2006
Пол: Мужской
Re: declspec(__dllimport) и операция взятия адреса
Ответ #11 - 18. Мая 2008 :: 05:43
Печать  
kms писал(а) 18. Мая 2008 :: 02:21:
Uzhast писал(а) 18. Мая 2008 :: 01:56:
Ну, 9-й Интел тоже не так уж сильно тормозит Улыбка

Ну... да...
Но вообще, release у меня собирается около минуты, а здесь - 12 сек.

Полный ребилд! В релизе! Минуту!... Детский сад  Смех


kms писал(а) 18. Мая 2008 :: 02:21:
А попробуй Йоксель собрать в VS, соберется? Подмигивание (Я MFC и ATL из PSDK брал, остальное - из VS8 или VS9; STLPort - не брал, boost - брал).

Все нормально компилируется - только в паре мест понадобилось добавить typename. И это называется более строгим контролем? Улыбка

Для линковки захотел Буста... Да ну нафиг. Я еще помню, как пытался перейти на IC10, New PSDK и VS2008. Бррр! kms, если хочешь, переходи. А я пас. По крайней мере, не сейчас - точно. Хочется над проектом работать, а не компиляторы менять. Тем более, что выгод он мне не принесет. Особо заметной строгости при компиляции он не добавляет (пара typename - ерунда). Скорость мне тоже ничего не даст. У меня основной тестовый dll-модуль весит 10Мб (при сборке он на какое-то время вырастает еще в 2-3 раза). И основные тормоза у меня при линковке. Иногда дебаггерная сборка после модификации всего одного cpp-файла происходит больше минуты. На этом фоне твой релизный ребилд за минуту - полная фигня. Улыбка И зачем тебе такой гемор ради выигрыша всего в 10-20 секунд на полный ребилд?... Блин, если бы я тебе сказал, сколько у меня все тестовые dll собираются в релизе, тебя бы точно кондрат хватил от таких чисел  Подмигивание Короче, хочешь переходи. Если еще найдешь способ быстро переключать настройку каталогов для Студии или способ поставить две одинаковые студии с разными настройками, то вообще хорошо.

kms писал(а) 18. Мая 2008 :: 02:21:
А где такое видел? (правда не помню)

Да любое использование CString в связи с 1С.
Например, прямой доступ к члену CString в объекте CValue. Если там уже есть значение, выделенное 1С, то при записи туда чего-то нового может понадобиться освободить и заново выделить память. Освобождаем память выделенную 1С. Выделяем память через свою CRT. Потом при уничтожении CValue 1С будет освобождать нашу память.

Всякие еще сохранения CValue в CString... Вообще, функций, которые принимают ссылку или указатель на наш объект CString хватает. Это что вспомнилось.

Ага, вот еще что вспомнил - контексты. При создании контекста одинэсина вызывает НАШУ функцию, которая выделяет память. А удаляет контекст она САМА через delete. Правда, вроде бы там в vtable должен быть адрес нашего operator delete...  Круглые глаза Хм...

kms писал(а) 18. Мая 2008 :: 02:21:
Кстати, я тут подумал - все равно с CDataRow плохо получилось.
Ибо выделяется она поставщиком - а удаляется контролом - неправильный интерфейс.
Надо, видать, самоликвидацию сделать, типа Release(), и заменить мои простые shared_ptr на shared_ptr с ликвидаторами.

Ага, как раз хотел предложить изменить интерфейс провайдера - добавить передачу смартпойнтеров вместо простых указателей.

kms писал(а) 18. Мая 2008 :: 02:21:
А, да, посмотрел на new/delete и malloc/calloc/sbheap в VS6/VS9 crt.
Близнецы-братья, только в VS9 оставлены только multithreaded WINHEAP варианты, и некоторые неточности исправлены.
Так что, думаю, все нормально будет, даже с похмелюги и в понедельник. Улыбка

Будем надеяться. Улыбка
  
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: declspec(__dllimport) и операция взятия адреса
Ответ #12 - 18. Мая 2008 :: 11:54
Печать  
Uzhast писал(а) 18. Мая 2008 :: 05:43:
Например, прямой доступ к члену CString в объекте CValue. Если там уже есть значение, выделенное 1С, то при записи туда чего-то нового может понадобиться освободить и заново выделить память. Освобождаем память выделенную 1С. Выделяем память через свою CRT. Потом при уничтожении CValue 1С будет освобождать нашу память.

Всякие еще сохранения CValue в CString... Вообще, функций, которые принимают ссылку или указатель на наш объект CString хватает. Это что вспомнилось.

Просто в работе с существующим объектом CString - нет небезопасного перехода.
Для выделения и освобождения памяти внутри CString используется одна CRT, все это инкапсулировано внутри CFixedAlloc и т.п.
У CValue есть operator=(LPCSTR), так что никакой прямой доступ не нужен.

Сохранение CValue в CString сделано через ссылку - тоже все нормально.
Так что надо дальше думать.

Цитата:
Ага, вот еще что вспомнил - контексты. При создании контекста одинэсина вызывает НАШУ функцию, которая выделяет память. А удаляет контекст она САМА через delete. Правда, вроде бы там в vtable должен быть адрес нашего operator delete...  Круглые глаза Хм...

В vtable там адрес деструктора - это хорошо, но мало.
Но еще здесь задействованы CObject:: operator new/delete - так что проблем нет.

Цитата:
Ага, как раз хотел предложить изменить интерфейс провайдера - добавить передачу смартпойнтеров вместо простых указателей.

Может, просто operator new/delete к CDataRow добавить?

Цитата:
kms писал(а) 18. Мая 2008 :: 02:21:
А, да, посмотрел на new/delete и malloc/calloc/sbheap в VS6/VS9 crt.
Близнецы-братья, только в VS9 оставлены только multithreaded WINHEAP варианты, и некоторые неточности исправлены.
Так что, думаю, все нормально будет, даже с похмелюги и в понедельник. Улыбка

Будем надеяться. Улыбка

На самом деле, вопрос, похоже, вообще из другой оперы.
При линковке с mfc42 глобальные operator new и operator delete берутся оттуда, так что риск налететь на грабли вообще минимален.

P.S.
Смейся-смейся. Улыбка
Речь ведь не идет о моментальном переходе, просто важно понять, насколько это возможно.
  

De quelle planète es-tu?
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: declspec(__dllimport) и операция взятия адреса
Ответ #13 - 18. Мая 2008 :: 12:07
Печать  
kms писал(а) 18. Мая 2008 :: 11:54:
При линковке с mfc42 глобальные operator new и operator delete берутся оттуда, так что риск налететь на грабли вообще минимален.

Единственно, уточню еще, что в mfc42 определены только простые скалярные операторы new/delete.

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

Но факт остается фактом: межмодульное взаимодействие - тема серьезная.

P.S.
Любовь как истина - сложна и как полынь горька... Улыбка
  

De quelle planète es-tu?
Наверх
 
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: declspec(__dllimport) и операция взятия адреса
Ответ #14 - 18. Мая 2008 :: 14:54
Печать  
Uzhast писал(а) 18. Мая 2008 :: 05:43:
Все нормально компилируется - только в паре мест понадобилось добавить typename. И это называется более строгим контролем? Улыбка

Ну, во-первых, Intel очень не плох, мы же не зря его выбрали.
Скажем, вот такие штуки VS не отслеживает:
Код
Выбрать все
warning #1595: non-POD (Plain Old Data) class type passed through ellipsis
warning #1125: function "CBLContext::GetPropName(int, int) const" is hidden by "CCellAppearance::GetPropName" -- virtual function override intended?
 


Во-вторых, ты, видать, нормально код пишешь - так что тебе компилятор можно вообще без диагностики брать. Очень довольный

Зато VS отслеживает использование POSIX, signed/unsigned, при взятии адреса функции требует "&".
И что для меня самое главное - просто так не позволяет опасных операций над указателями на функции члены.

Не поленись, сравни прикрепленный исходник c CVS/icpp
Ты увидишь, что пришлось поменять такие моменты:

Код
Выбрать все
BL_METH("SetRowsPictures", "УстановитьКартинкиСтрок", 2, &MethSetRowsPictures, NULL, DefSetRowsPictures)
error C4867: 'CV7GridColumn::DefSetRowsPictures': function call missing argument list; use '&CV7GridColumn::DefSetRowsPictures' to create a pointer to member
 



Код
Выбрать все
m_CommandQueue.Add(&CCursorGridCtrl::OnActivateRow);
error C2276: '&' : illegal operation on bound member function expression
 


и это правильно

- пришлось избавиться от директив #import

Код
Выбрать все
CMapOfInfoUnlimitsParamsPtr& GetBindInstanceValueList() const
{ return m_BindInstanceValueList; }

error C2440: 'return' : cannot convert from 'const CMapOfInfoUnlimitsParamsPtr' to 'CMapOfInfoUnlimitsParamsPtr &'
 


и это правильно

Что осталось:
Код
Выбрать все
warning C4018: '<' : signed/unsigned mismatch
 



Код
Выбрать все
warning C4244: '=' : conversion from 'double' to 'USHORT', possible loss of data
 



- POSIX
- unrefd local variables

Код
Выбрать все
GlobalMethods.h	warning C4996: 'swprintf': swprintf has been changed to conform with the ISO C standard, adding an extra character count parameter. To use traditional Microsoft swprintf, set _CRT_NON_CONFORMING_SWPRINTFS.
 


наконец-то получил вменяемое сообщение

Код
Выбрать все
Preprocessor.h: std::auto_ptr<CRangesOfDescrImpl> m_pImpl;
warning C4150: deletion of pointer to incomplete type 'CRangesOfDescrImpl'; no destructor called
 


Что там удаляет auto_ptr под ICL - не известно

Код
Выбрать все
DynaValue.cpp	    if (pContext != NULL && pContext->GetRuntimeClass()->m_lpszClassName == "CComponentClass")
warning C4130: '==' : logical operation on address of string constant
 


ха-ха Улыбка
  

De quelle planète es-tu?
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: [1] 2 3 
ОтправитьПечать