Есть глобальный массив. Он во внешней dll. Компилятор генерирует Код (Text): mov eax, offset FullProjectIdent mov eax, offset FullProjectIdent - 4 обе команды как я понимаю кодируются в одно число. Тогда как должен поступать компилятор при генерации и программист при написании чтобы заработало смещение -4? offset ссылается на импорт.
Эти две команды не кодируются в одно число. В еах записывается не один и тот же оффсет, а в целом- нихрена не понятно что вам нужно.
Я имел ввиду что offset будет числом и в первой и второй строке. Только во второй строке адрес будет на 4 меньше. Вопрос как такая ссылка должна строиться на импорт?
Если смещение прописано как Код (Text): offset FullProjectIdent - 4 у нас есть проблемный адрес, я непонимаю как он должен правильно выглядить для связи с экспортов другого модуля. Если же написано Код (Text): offset FullProjectIdent + 4 * ebx , то у нас есть отдельный адрес который указывает на импорт а смещение выясняется в точке вызова. Может быть надо сообщать компилятору о том что это импорт массива чтобы он генерировал правильный код?
Стандартная практика для системных модулей 2к и в некоторых случаях ХП. Обе длл грузятся по фиксированным адресам, и у них перекрестные офсеты друг на друга. В вашем же случае похоже, что идет указатель на таблицу импорта. И оттуда уже идет вызов. Что-то вроде: mov eax, offset IAT call [eax] mov eax, offset IAT + 4 call [eax] Присоединяюсь к трешгену. Объясните внятнее, что требуется. Либо уточните вопрос
Есть глобальный массив FullProjectIdent. Он экспортируется из 2.dll в 1.exe. В 1.еxe при его использовании компилятор генерирует код, который можно выделить в две группы: а. В коде идет адрес, затем независимая от него операция с регистрами для индексации. б. В коде идет адрес + некое смещение (4, 8, ..., 128, ...). Оба адреса должны указывать на импорт, но второй случай после обработки фиксапов не прокатывает поскольку содержит неверное смещение. Мне нужно чтобы код заработал. Возможно я что-то недопонимаю. Мое предположение заключается в том что компилятору можно намекнуть ключом командной строки генерировать правильный код, но что-то для Borland 4.5 ненашел пока. Правильно ли я думаю? Возможно есть другие версии, предложения?
Ненашел ничего подходящего. При наличии или отсутствии генерации офсеты сохраняются такими же с фиксированными смещениями. Код (Text): Borland 4.5 Command-Line Options Option Description +filename Use alternate configuration file named filename @filename Read compiler options from the response file filename -1- Generate 8086 compatible instructions. -1 Generate the 80186/286 compatible instructions (16-bit only). -2 Generate 80286 protected-mode compatible instructions (16-bit compiler only) (Default for 16-bit) -3 Generate 80386 protected-mode compatible instructions. (Default for 32-bit compiler) -4 Generate 80386/80486 protected-mode compatible instructions. -5 Generate Pentium protected-mode compatible instructions. -a Byte alignment. (Default: -a- do not use byte-aligning.) -A Use only ANSI keywords. (Extentions like the far and near modifier no longer recognized.) -AK Use only Kernigham and Ritchie keywords. -an Align to n. 1=byte, 2=word (2 bytes), 4=double word (4 bytes\2 words 32 bit target only), 8=quad word (8 bytes\4 words 32 bit target only) -AT Use Borland C++ keywords (Alternately specified by -A-) -AU Use UNIX V keywords. (Extentions like the far and near modifier no longer recognized.) -B Compiles assembly and calls TASM or TASM32. If you don't have TASM in your path, checking this option generates an error. Also, old versions of TASM might have problems with 32-bit generated assembler code. -b Make enums always integer-sized. (Default: -b- make enums byte-sized when possible.) Note: Changing this default is not recommended. -c Compiles and assembles the named source files, but does not execute a link command. -C Turn nested comments on. (Default: -C- turn nested comments off.) -d Merge duplicate strings. (Default) -dc Move string literals from data segment to code segment (16-bit compiler only) -Didentifier Define identifier to the null string. -Didentifier=string Define identifier to string. -efilename Derives the executable program's name from filename by adding the file extension .EXE (the program name is then filename.EXE). filename must immediately follow the -e, with no intervening whitespace. Without this option, the linker derives the .EXE file's name from the name of the first source or object file in the file name list. -Efilename Use filename as the name of the assembler to use. (Default = TASM) -f Emulate floating point. (Default) -f287 Use 80287 hardware instructions (16-bit compiler only). -F Uses fast huge pointers. -Fc Generate COMDEFs (16-bit compiler only). -Ff Create far variables automatically. -ff Fast floating point. (Default) -Ff=size Create far variables automatically; set the threshold to size, where size is 0 to 65535 (16-bit target only). -Ff=1 Array variable 'identifier' is near warning. (Default) -Fm Enables all the other -F options (-Fc, -Ff, and -Fs). Use this to quickly port code from other 16-bit compilers. -Fs Assume DS=SS in all memory models (16-bit compiler only). -G Optimize code for speed. (Default: -G- optimize code for size.) -gn Stop compiling after n messages. (Default: 100.) -H Generate and use precompiled headers. (Default) -Hfilename Sets the name of the file for precompiled headers -h This option offers an alternative method of calculating huge pointer expressions; this method is much faster than the standard method, but must be used with caution. When you use this option, huge pointers are normalized only when a segment wraparound occurs in the offset part. This causes problems with huge arrays if any array elements cross a segment boundary. -H=filename Set the name of the file for precompiled headers to filename. -Hc Cache precompiled headers. Use with -H, -Hxxx, -Hu, or -Hfilename. This option is useful when compiling more than one precompiled header. (32-bit compiler only) -Hu Use but do not generate precompiled headers. -in Make significant identifier length to be n, where n is between 8 and 250. (Default) -Ipath Set search path for directories for include files to path. -Jg Generate definitions for all template instances and merge duplicates. (Default) -Jgd Generate public definitions for all template instances; duplicates result in redefinition errors. -Jgx Generate external references for all template instances. -jn Errors: stop after n messages. (Default = 25) -K Default character type unsigned. (Default: -K- default character type signed.) -k Turn on standard stack frame. (Default) -K2 Allow only two character types (signed and unsigned). Char is treated as signed. Allows compatibility with Borland C++ 3.1 and earlier. -Lpath Set search path for library files. -lx Pass option x to the linker (TLINK for BCC and TLINK32 for BCC32). More than one option can appear after the -l (which is a lowercase L). -M Instruct linker to create a full link map. -mc Compile using compact memory model (16-bit compiler only). -mh Compile using huge memory model. -ml Compile using large memory model (16-bit compiler only). -mm Compile using medium memory model (16-bit compiler only). -mm! Compile using medium memory model;assume DS!=SS (16-bit compiler only). (Note: there is no space between the -mm and the !.) -ms Compile using small memory model (16-bit compiler only). (Default) -ms! Compile using small memory model; assume DS! = SS (16-bit compiler only). (Note: there is no space between the -ms and the !.) -mt Compile using tiny memory model. -mt! Compile using tiny memory model. (Note: there is no space between the -mt and the !.) -N Check for stack overflow. -npath Set the output directory to path. -O Optimize jumps. -O1 Generate smallest possible code (same as using -O, -Ob, -Oe, -Og, -Oi, -Ol, -Om, -Op, -Ot, -Ov, -k-, -Oc, and -Z). -O2 Generate fastest possible code. -Oa Optimize assuming pointer expressions are not aliased on common subexpression evaluation. -Ob Eliminate dead code. -Oc Eliminate duplicate expressions within basic blocks. -Od Disable all optimizations. -Oe Allocate global registers and analyze variable live ranges. -ofilename Compile source file to filename.OBJ. -Og Eliminate duplicate expressions within functions. -Oi Expand common intrinsic functions. -Ol Compact loops. -Om Move invariant code out of loops. -Op Propagate copies. -Ot Generate fastest code (executable speed); Microsoft compatible. -Ov Enable loop induction variable and strength reduction. -OW Suppress the inc bp/dec bp on windows far functions (16-bit compiler only). -Ox Generate fastest code (executable speed); Microsoft compatible. -P Perform a C++ compile regardless of source file extension. (Default when extention is not specified. This is an uppercase P.) -p Use Pascal calling convention. (This is a lowercase p.) -pc Use C calling convention. (Default same as -pc or -p-) -Pext Perform a C++ compile regardless of source file extension and set the default extension to ext. This option is available because some programmers use .C or another extension as their default extension for C++ code. -po Use fastthis calling convention for passing this parameter in registers (16-bit compiler only). -pr Use fastcall calling convention for passing parameters in registers. -ps Use stdcall calling convention (32-bit compiler only). -R Include browser information in generated .OBJ files. -r Use register variables. (Default) -rd Allow only declared register variables to be kept in registers. -RT Enable runtime type information. (Default) -S Generate assembler source compiles the named source files and produces assembly language output files (.ASM), but does not assemble. When you use this option, Borland C++ includes the C or C++ source lines as comments in the produced .ASM file. -T- Remove all previous assembler options. -Tstring Pass string as an option to TASM, TASM32, or assembler specified with -E. -tW Make the target a Windows .EXE with all functions exportable. (Default) -tWC Make the target a console .EXE. -tWCD Make the target a console .DLL, all functions exportable -tWCDE Make the target a console .DLL, explicit functions exportable -tWD Make the target a Windows .DLL with all functions exportable. -tWDE Make the target a Windows .DLL with explicit functions exportable. -tWE Make the target a Windows .EXE with explicit functions exportable. -tWM Make a multithreaded application or DLL. -tWS Make the target a Windows .EXE that uses smart callbacks (16-bit compiler only). -tWSE Make the target a Windows .EXE that uses smart callbacks, with explicit functions exportable and exported (16-bit compiler only). -u Generate underscores for symbols. (Default) -Uname Undefines any previous definitions of the named identifier name. -v Turn on source debugging. -V Create smart C++ virtual tables. (Default) -V0 Create external C++ virtual tables. -V1 Create public C++ virtual tables. -Va Pass class arguments by reference to a temporary variable (16-bit compiler only). -Vb Make virtual base class pointer the same size as the 'this' pointer of the class (16-bit compiler only). (Default) -Vc Do not add the hidden members and code to classes with pointers to virtual base class members (16-bit compiler only). -Vf Far C++ virtual tables (16-bit compiler only). -Vh Treat 'far' classes as 'huge' (16-bit compiler only) When on, the compiler treats all __far classes as __huge. -vi Turn on inline expansion (-vi- turns off inline expansion). -Vmd Use the smallest representation for member pointers. -Vmm Member pointers support multiple inheritance. -Vmp Honor the declared precision for all member pointer types. -Vms Member pointers support single inheritance. -Vmv Member pointers have no restrictions (most general representation). (Default) -Vo Set all backward compatible switches. Use this when linking with libraries built with an older version of Borland C++. -Vp Pass the 'this' parameter to 'pascal' member functions as the first. -Vs Local C++ virtual tables. -Vt Place the virtual table pointer after nonstatic data members (16-bit compiler only). -Vv This option directs the compiler not to change the layout of any classes (which it needs to do to allow pointers to virtual base class members, which were not supported in previous versions of Borland C++). If this option is used, the compiler will not be able to create a pointer to a member of a base class that can be reached only from the derived class through two or more levels of virtual inheritance. -W Creates a Windows GUI application. -w Display warnings on. -w! Do not compile to .OBJ if warnings were found. (Note: there is no space between the -w and the !.) -wamb Ambiguous operators need parentheses. -wamp Superfluous & with function. -wasm Unknown assembler instruction. -waus 'identifier' is assigned a value that is never used. (Default) -wbbf Bit fields must be signed or unsigned int. -wbei Initializing 'identifier' with 'identifier'. (Default) -wbig Hexadecimal value contains more than three digits. (Default) -WC Creates a 32-bit console mode application. -wccc Condition is always true OR Condition is always false. (Default) -WCD Creates a 32-bit console mode DLL with all functions exportable and exported. -WCDE Creates a 32-bit console mode DLL with explicit functions exportable and exported. -wcln Constant is long. -wcpt Nonportable pointer comparison. (Default) -WD Creates a GUI DLL with all functions exportable. -WDE Creates a GUI DLL with explicit functions exportable and exported. -wdef Possible use of 'identifier' before definition. -wdpu Declare type 'type' prior to use in prototype (Default) -wdsz Array size for 'delete' ignored. (Default) -wdup Redefinition of 'macro' is not identical (Default) -WE Make the target a Windows .EXE with explicit functions exportable and exported. -weas 'type' assigned to 'enumeration'. (Default) -weff Code has no effect. (Default) -wext 'identifier' is declared as both external and static (Default) -whch Handler for '<type1>' Hidden by Previous Handler for '<type2>' -whid 'function1' hides virtual function 'function2' (Default) -wibc Base class '<base1>' is also a base class of '<base2>' (Default) -will Ill-formed pragma. (Default) -winl Functions containing reserved words are not expanded inline (Default) -wlin Temporary used to initialize 'identifier'. (Default) -wlvc Temporary used for parameter 'parameter' in call to 'function' (Default) -WM Make a multithreaded application or DLL. -wmpc Conversion to type fails for members of virtual base class base. (Default) -wmpd Maximum precision used for member pointer type type. (Default) -wmsg User-defined warnings . This option allows user-defined messages to appear in the IDE message window. -wnak Non-ANSI Keyword Used: '<keyword>' (Note: Use of this option is a requirement for ANSI conformance.) -wncf Non-const function 'function' called for const object. (Default) -wnci The constant member 'identifier' is not initialized. (Default) -wnod No declaration for function 'function' -wnsf Declaration of static function 'func(...)' ignored. -wnst Use qualified name to access nested type 'type' (Default) -wntd Use '> >' for nested templates instead of '>>'. (Default) -wnvf Non-volatile function function called for volatile object. (Default) -wobi Base initialization without a class name is now obsolete (Default) -wobs Identifier is obsolete. (Default) -wofp Style of function definition is now obsolete. (Default) -wovl Overload is now unnecessary and obsolete. (Default) -wpar Parameter 'parameter' is never used. (Default) -wpch Cannot create precompiled header: header. (Default) -wpia Possibly incorrect assignment. (Default) -wpin Initialization is only partially bracketed. -wpre Overloaded prefix operator 'operator' used as a postfix operator. -wpro Call to function with no prototype. (Default) -wrch Unreachable code. (Default) -wret Both return and return of a value used. (Default) -wrng Constant out of range in comparison. (Default) -wrpt Nonportable pointer conversion. (Default) -wrvl Function should return a value. (Default) -WS Make the target a Windows .EXE that uses smart callbacks (16-bit compiler only). -WSE Make the target a Windows .EXE that uses smart callbacks, with explicit functions exportable (16-bit compiler only). -wsig Conversion may lose significant digits. -wstu Undefined structure 'structure' -wstv Structure passed by value. -wsus Suspicious pointer conversion. (Default) -wucp Mixing pointers to different 'char' types. -wuse 'identifier' declared but never used. -wvoi Void functions may not return a value. (Default) -wxxx Enable xxx warning message. (Default) -wzdi Division by zero (Default) -X Disable compiler autodependency output. (Default: -X- use compiler autodependency output.) -x Enable exception handling. (Default) -xc Enable compatible exception handling. -xd Enable destructor cleanup. (Default) -xf Enable fast exception prologs. -xp Enable exception location information. -Y Generate overlay-compatible code. (16-bit compiler only) -Yo Overlay compiled files. (16-bit compiler only) -y Line numbers on. -Z Enable register load suppression optimization. -zAname Code class set to name. -zBname BSS class set to name. -zCname Code segment class set to name. -zDname BSS segment set to name. -zEname Far segment set to name (16-bit compiler only). -zFname Far class set to name (16-bit compiler only). -zGname BSS group set to name. -zHname Far group set to name (16-bit compiler only). -zPname Code group set to name. -zRname Data segment set to name. -zSname Data group set to name. -zTname Data class set to name. -zVname Far virtual segment set to name (16-bit compiler only). -zWname Far virtual class set to name (16-bit compiler only). -zX* Use default name for X. For example, -zA assigns the default class name CODE to the code segment class.
Код (Text): extern BYTE * FullProjectIdent[]; extern BYTE ** VarTest; extern BYTE ** VarTest2; void AsmTest(void) { /* push ebp mov ebp,esp add esp,-52 push ebx */ BYTE Buff[ 50 ]; int i; //не инициализируем т.к. не используем BYTE c = **VarTest; /* mov eax,dword ptr [_VarTest] mov eax,dword ptr [eax] mov al,byte ptr [eax] */ *VarTest2[2] = c; //ok /* ?live1@48: ; EBX = i, EAX = c mov edx,dword ptr [_VarTest2] mov edx,dword ptr [edx+8] mov byte ptr [edx],al */ // for( i = 0; FullProjectIdent[ i ] != NULL; i++ ) ; Convert(Buff, (DWORD)&FullProjectIdent[i - 1]); //err /* ?live1@60: ; EBX = i mov eax,ebx shl eax,2 add eax,offset _FullProjectIdent-4 //проблема именно здесь //иногда генерируется нормальный код где сначала в регистр кладется offset, а потом с ним производятся любые нормальные действия push eax lea eax,dword ptr [ebp-52] push eax call _Convert add esp,8 */ }
Ну и что ты хочешь? Раз объявляешь статический массив, то его адрес после линковки д.б. известным = const, поэтому ес-но компилятор вправе сразу вычислять и подставлять значений выражений типа const-4 и т.п., т.к. "от перестановки мест слагаемых сумма не меняется". Если же речь идет об импорте, то нужно обявлять не сам статический массив, а указатель на него - тогда компилер д.б.сначала загрузить значение ук-ля и только потом прибавлять к нему смещения
Видимо, всё же не поддерживается. Зато в bcc32 5.5 есть ключевое слово _import (extern _import BYTE * FullProjectIdent[] – как-то так?). В хелпе 4.5 оно тоже упоминается. Попробуйте? Почему, кстати, используете такой древний компилятор?
NoName, попробовал сам в 5.5.1. _import + массив BYTE-ов – ок, _import + массив BYTE * – та самая проблема, без _import – проблема. Но забавно то, что с typedef BYTE * BYTEPTR; extern _import BYTEPTR FullProjectIdent[100]; генерируется верный код (это объектник, EXE не собирал): Код (Text): ; return *FullProjectIdent[0] + *FullProjectIdent[1] + *FullProjectIdent[-1]; mov eax, dword ptr ds:_FullProjectIdent mov edx, [eax] xor eax, eax mov al, [edx] mov edx, dword ptr ds:_FullProjectIdent mov ecx, [edx+4] xor edx, edx mov dl, [ecx] add eax, edx mov ecx, dword ptr ds:_FullProjectIdent mov edx, [ecx-4] xor ecx, ecx mov cl, [edx] add eax, ecx
iZzz32 И что тут забавного - неужели не понятно, что экспо- и импо-ртироваться могут только указатели на функции, структуры, массивы, а не сами "тела" этих функций, структур, массивов?!
Да, но dllimport/_import скрывают это. Компилятор неявно дереференсит указатель из IAT и extern __declspec(dllimport) int foo; для программиста ведёт себя так, как обычная глобальная переменная. Что тут забавного: а разве поведение VOID * foo и PVOID foo должно отличаться?
iZzz32 Пардон, погорячился Похоже от сишного звездно-заднепроходного синтаксиса не только у меня крыша едет, но и у бцб-шного компилера тоже Поэтому мысль заключалась в том, что лучше не пудрить мозги ни себе, ни компилеру и определить тип всего массива через typedef. Но оказалось, что достаточно просто "убрать звездочку" - действительно забавно