Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Вопросы по программированию на C/С++

Автор: kkuuhhaa
Дата сообщения: 05.12.2013 14:54
ne_viens
http://s2.ipicture.ru/uploads/20131205/JUzRW5MD.jpg
как здесь картинки грузятся?
Автор: ne_viens
Дата сообщения: 05.12.2013 15:09
Может быть в 01.c такое:

__declspec(dllexport) void foo(void)
{
}

лежит?
Автор: kkuuhhaa
Дата сообщения: 05.12.2013 15:25
ne_viens
Это есть в bzlib.h
#ifndef __GNUC__
# define __DLL_IMPORT__ __declspec(dllimport)
# define __DLL_EXPORT__ __declspec(dllexport)
# else
# define __DLL_IMPORT__ __attribute__((dllimport)) extern
# define __DLL_EXPORT__ __attribute__((dllexport)) extern
# endif

И как это связано с построением статической библиотеки? Убрать __GNUC__?
Автор: ne_viens
Дата сообщения: 05.12.2013 15:49
Какой-то странный bzlib.h
Скачай последний bzip c bzip.org/downloads.html (tarball).
Автор: kkuuhhaa
Дата сообщения: 05.12.2013 16:01
ne_viens
Скачено с порта на винду. последняя версия 1.0.5 дата файла 20.03.08 http://gnuwin32.sourceforge.net/packages/bzip2.htm Зачем повторять работу? Было всего лишь один варинг, работает ведь
Автор: nick7inc
Дата сообщения: 05.12.2013 16:43
Добрый вечер. Нужен совет по весьма специфическому вопросу. Пишу программу для снятия данных с прибора. Язык C++, компилятор GCC 3.4.2 (MinGW). Использую DLL фирмы-производителя прибора. Описание есть, то есть не угадываю.

При компиляции в режиме отладки работает программа без проблем. Но при компиляции в режиме Release программа вылетает с ошибкой. Тип ошибки либо Segmentation fault, либо Illegal instruction.

[more=далее]Выяснил, что проблема появляется при включении режима оптимизации -O1 или -O2, который подставляет код inline функций вызова внешней функции DLL прямо в код программы. У одной такой функции убрал inline, в конкретном месте проблема исчезла.

Отладчиком выяснил, что вылет происходит после return'а той функции, в которую подставили код inline функции. В проблемном месте return возвращает управление не в ту, функцию, которая вызвала текущую, а создаётся впечатление, что в случайное место. Складывается такое ощущение, что при вызове функции внешней DLL портится какой-то регистр.

Код:
inline int AVS_GetList (unsigned int a_ListSize, unsigned int* a_pRequiredSize,
struct AvsIdentityType* a_pList)
{
if (!dll.AVS_GetList) return ERR_INVALID_DLL_VERSION;
const int res = dll.AVS_GetList (a_ListSize, a_pRequiredSize, a_pList);
//dll - структура с указателями на функции DLL

return res;
}
Автор: Abs62
Дата сообщения: 05.12.2013 17:27
nick7inc

Цитата:
Отладчиком выяснил, что вылет происходит после return'а той функции, в которую подставили код inline функции. В проблемном месте return возвращает управление не в ту, функцию, которая вызвала текущую, а создаётся впечатление, что в случайное место. Складывается такое ощущение, что при вызове функции внешней DLL портится какой-то регистр.

ESP портится, надо полагать. Такое может быть, если тип вызова не соответствует типу функции. Если, скажем, скомпилирована функция как __cdecl, а вызывается как __stdcall. Или наоборот. Потому что __cdecl и __stdcall по-разному очищают стек от переданных в функцию параметров.
Автор: nick7inc
Дата сообщения: 06.12.2013 09:19
Abs62

Цитата:
тип вызова не соответствует типу функции

Вполне может быть. В SDK для прибора, которым я пользуюсь, нет набора .h и .lib для конкретно моей среды разработки. У меня GCC, а там есть только для Borland C++Builder 5, Codegear C++Builder 2009 и vcpp2008 (для С++). Поэтому мне приходится загружать функции из DLL вручную при помощи LoadLibrary() и GetProcAddress(). Прототип функций я взял из заголовочного файла Borland C++Builder 5:

Код: DLL_API int __stdcall AVS_GetList
( unsigned int a_ListSize, unsigned int* a_pRequiredSize, AvsIdentityType* a_pList);
Автор: ne_viens
Дата сообщения: 06.12.2013 09:33
.lib можно из .h сделать.
Тогда отпадёт надобность в GetProcAddress(LoadLibrary(""), "");
Автор: nick7inc
Дата сообщения: 06.12.2013 09:47
ne_viens

Цитата:
.lib можно из .h сделать.

Да мне не трудно через GetProcAddress(). Замена __stdcall на __cdecl проблему не решила. Я не уверен в прототипе функций, описанных в заголовке для Borland C++Builder 5. Всё, что у меня сейчас есть, это DLL, описание в PDF (где ни о __stdcall, ни о __cdecl ни слова не сказано) и пример-исходник программы для Borland C++Builder 5, для коего есть LIB, но которым я не могу воспользоваться..
Автор: ne_viens
Дата сообщения: 06.12.2013 10:08
Из борландовского .h явно видно, что ф-я __stdcall.
Если ее вызывать по __cdecl соглашению, ошибка будет в любом случае- оптимизирован код или нет.
Автор: nick7inc
Дата сообщения: 06.12.2013 10:13
ne_viens

Цитата:
ошибка будет в любом случае- оптимизирован код или нет.

Без оптимизации не проявляется, возможно из-за обёрточной функции.
Автор: ne_viens
Дата сообщения: 06.12.2013 10:42
Ну незнаю, у меня и без -О и с -О работает:

Код: //gcc -Wall -O3 err.c -o err.exe

#include <windows.h>
#include <stdlib.h>

#define ERR_INVALID_DLL_VERSION -8
struct AvsIdentityType {int i, j;};
typedef int (__stdcall *_AVS_GetList)(unsigned int, unsigned int*, struct AvsIdentityType*);
typedef struct {
    char c;
    int i;
    _AVS_GetList AVS_GetList;
//    other functions follow
} PACK;

PACK dll;
/////////////////////////////////////////////////////////////////////////////////////////////
inline int AVS_GetList(unsigned int a_ListSize, unsigned int* a_pRequiredSize,
                        struct AvsIdentityType* a_pList)
{
    if(!dll.AVS_GetList) return ERR_INVALID_DLL_VERSION;
    const int res = dll.AVS_GetList (a_ListSize, a_pRequiredSize, a_pList);
    
    return res;
}

/////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
    unsigned int i;
    int j;
    struct AvsIdentityType ait;
    
    dll.AVS_GetList = GetProcAddress(LoadLibrary("avslib.dll"), "AVS_GetList");
    j = dll.AVS_GetList(1, &i, &ait);
    return j;
}
Автор: Abs62
Дата сообщения: 06.12.2013 10:56
nick7inc

Цитата:
Без оптимизации не проявляется, возможно из-за обёрточной функции.

Угу, судя по дисассемблированному коду, оператор "mov %ebp,%esp" восстанавливает ESP, что бы с ним внутри функции ни происходило.
Думаю, тут надо смотреть в отладчике, пошагово проходя дисассемблированный код. После всех манипуляций с передачей параметров и вызова функции значение ESP должно вернуться к тому, что было до того. Если этого не происходит, надо разбираться, что именно тут не так.
Кстати, тут же можно и сразу посмотреть, какого типа на самом деле вызываемая функция. Если после возврата из "call *%edx" ESP меняется, это stdcall, если нет - cdecl (это касается функций с параметрами, если параметров нет, ESP в любом варианте не поменяется).
Автор: nick7inc
Дата сообщения: 06.12.2013 11:48
Abs62, ne_viens
Спасибо большое за наставления. Постараюсь позже поэкспериментировать с ассемблером (посмотрю за ESP) (сейчас студент грузит). В качестве маркеров начала кода вызова функции вставлю asm("nop") перед и после вызова функции.

P.S. Abs62 Значение ESP должно меняться, когда начинается подготовка параметров для передачи функции?
Автор: Abs62
Дата сообщения: 06.12.2013 12:09
nick7inc

Цитата:
P.S. Abs62 Значение ESP должно меняться,  когда начинается подготовка параметров для передачи функции?

А это как разработчики компилятора реализовали, так и будет. В классическом варианте да, параметры загоняются в стек командой "push". А MinGW 4.8.1, к примеру (на других версиях не смотрел), пользуется "mov", не меняя значения ESP.
Автор: ne_viens
Дата сообщения: 06.12.2013 12:10

Цитата:
...Значение ESP должно меняться, когда начинается подготовка параметров для передачи функции?


Для MCVC 32бит меняется, так как каждый аргумент передаётся инструкцией push, но для GCC обычно нет, так как GCC в начале каждой подпрограммы выделяет место для аргументов вложенных функций, а аргументам присваивает значения с
mov [esp], arg0
mov [esp+4], arg1
mov [esp+8], arg2
itd.
Автор: akaGM
Дата сообщения: 06.12.2013 13:14
а как же фастколлы через регистры, если попросить?
Автор: ne_viens
Дата сообщения: 06.12.2013 14:09
Там страшный бардак между компилерами/OSями, в каком регистре какой аргумент.
Автор: akaGM
Дата сообщения: 06.12.2013 14:34
да надо самому всё жёстко строго описывать, без всяких дефолтов...
Автор: nick7inc
Дата сообщения: 06.12.2013 17:31
Abs62

Цитата:
смотреть в отладчике, пошагово проходя дисассемблированный код

Оптимизация отключена, функция не inline. [more=Код]
Код: 00439C46    push %ebp
00439C47    mov %esp,%ebp
00439C49    sub $0x18,%esp
00439C4C    mov 0x8(%ebp),%eax
00439C4F    cmpl $0x0,0x10(%eax)
00439C53    jne 0x439c5e <Avantes_IO::Avantes::AVS_GetList(unsigned int, unsigned int*, Avantes_IO::AvsIdentityType*)+24>
00439C55    movl $0xffffffee,-0x8(%ebp)
00439C5C    jmp 0x439c83 <Avantes_IO::Avantes::AVS_GetList(unsigned int, unsigned int*, Avantes_IO::AvsIdentityType*)+61>
00439C5E    mov 0x8(%ebp),%edx
00439C61    mov 0x14(%ebp),%eax
00439C64    mov %eax,0x8(%esp)
00439C68    mov 0x10(%ebp),%eax
00439C6B    mov %eax,0x4(%esp)
00439C6F    mov 0xc(%ebp),%eax
00439C72    mov %eax,(%esp)
00439C75    mov 0x10(%edx),%eax
00439C78    call *%eax
00439C7A    mov %eax,-0x4(%ebp)
00439C7D    mov -0x4(%ebp),%eax
00439C80    mov %eax,-0x8(%ebp)
00439C83    mov -0x8(%ebp),%eax
00439C86    leave
00439C87    ret
Автор: Abs62
Дата сообщения: 06.12.2013 18:19
nick7inc

Цитата:
До 00439C78 значение ESP сохраняется. После call оно становиться (ESP=0x23fb8C)

Угу, функция stdcall. А вот компилятор вызывает её как cdecl, иначе после "call *%eax" стоял бы код "sub $0xc,%esp", возвращающий ESP в нужное положение. Проверьте объявление указателя на эту функцию.

Цитата:
после leave оно стало (ESP=0x23fb9C).

leave возвращает ESP в состояние, в каком он был перед "push %ebp".
Автор: nick7inc
Дата сообщения: 06.12.2013 18:22
Abs62
Кажется проблема решена (см. предыдущее сообщение). В объявлении typedef была ошибка, из-за чего компилер не считал эту функцию stdcall (не туда поставил ключевое слово).

Всем спасибо!

Добавлено:

Цитата:
leave возвращает ESP в состояние, в каком он был перед "push %ebp".

Понял.
Автор: kkuuhhaa
Дата сообщения: 11.12.2013 08:52
Как получить беззнаковое значение двух байт?
Для одного байта
char *source;
unsigned char *msg;    
msg=(unsigned char*) malloc(2);
msg = reinterpret_cast<unsigned char*>(source+19);

надо unsigned short из куска source

ЗЫ ne_viens С bzip2 оказывается подсовывал не ту б-ку. Надо libbz2.lib
Автор: nick7inc
Дата сообщения: 11.12.2013 12:28
kkuuhhaa
Вы указатель (адрес) присваиваете в качестве значения переменной.
Автор: kkuuhhaa
Дата сообщения: 11.12.2013 12:38
nick7inc
Ну исправил, про другое ж вопрос.
Автор: Abs62
Дата сообщения: 11.12.2013 13:04
kkuuhhaa

Цитата:
msg=(unsigned char*) malloc(2);

Зачем?

Цитата:
надо unsigned short из куска source

Дык, кто мешает кастовать указатель не к unsigned char*, а к unsigned short*?
Автор: suslovp
Дата сообщения: 11.12.2013 13:08
char *source;
unsigned short val;

val = *((unsigned short*)(source+19));

не?
Автор: kkuuhhaa
Дата сообщения: 11.12.2013 14:03
Abs62
suslovp
спасибо, оба варианта работают.
Автор: AlekseySerg
Дата сообщения: 11.12.2013 16:53
Всем доброго времени суток. Вот у же не первый день сижу и не одну книгу почитал. Не буду говорить, что нет того что надо. Просто может я не понимаю.
У меня есть выпадающее меню ComboBox в нем три строчки, при выборе одной из строчек в окне Edit должно автоматически вводится числовое значение, которое как-то надо присвоит конкретной строчке! Как это сделать!

Страницы: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193

Предыдущая тема: не знаю как назвать тему :-)


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.