Page 1 of 2
External .LIB compiles with ASM Backend, but not C Backend
Posted: Tue Sep 26, 2023 4:17 pm
by JoeC4281
I am using;
Code: Select all
PureBasic 6.00 LTS (Windows - x64)
Windows 10 [Version 10.0.19044.3086]
I have a library,
TakeCmd.lib
I want to use
Command from the
TakeCmd.lib (yes, it is actually called
Command)
shows me
Code: Select all
?Command@@YAHPEB_WH@Z (int __cdecl Command(wchar_t const *,int))
TakeCmd.h which shows me
Code: Select all
int WINAPI Command( LPCTSTR pszLine, int nReserved );
/*
Call the parser to expand and execute pszLine
nReserved - reserved, must be set to 0
which I then declare as an external function from
TakeCmd.lib
Code: Select all
ImportC "takecmd.lib"
Command_(*lpszString, nReserved.i) As "?Command@@YAHPEB_WH@Z"
EndImport
Executing the command;
compiles, and works, using
pbcompiler.exe (assembler backend)
However, using
pbcompilerc.exe (C backend), it does not compile, and returns 619 lines of errors;
Code: Select all
PureBasic 6.00 LTS - C Backend (Windows - x64)
Loading 'C' subsystem
Compiling ActiveScript.pb
Loading external libraries...
Starting compilation...
Including source: Modul_ActiveScript.pb
1877 lines processed.
Error: Assembler
purebasic.c: In function 'activescriptsiteXf_onscripterror':
purebasic.c:865:16: warning: passing argument 1 of 'SYS_CopyString' discards 'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]
SYS_CopyString(v_error);
^~~~~~~
.
.
.
purebasic.c:231:43: note: expected 'TCHAR *' {aka 'void *'} but argument is of type 'volatile void *'
M_SYSFUNCTION(void) SYS_FreeString(TCHAR *String);
~~~~~~~^~~~~~
C:\Users\jlcav\AppData\Local\Temp\ccF8Sg8s.s: Assembler messages:
C:\Users\jlcav\AppData\Local\Temp\ccF8Sg8s.s:3295: Error: invalid character '?' before operand 1
I'm okay with it compiling and working with the ASM Backend,
however,
after much time trying to figure out what was wrong in my code,
using the C Backend,
and finding nothing wrong with my code,
using the C Backend,
it was then that I thought to try compiling with the ASM Backend,
which works as it should.
Constructive suggestions as to why this code compiles with the ASM Backend,
but does not compile with the C Backend.
Joe
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Tue Sep 26, 2023 5:08 pm
by fryquez
PureBasic 6.00 LTS is bit old, have you tried latest beta of 6.03?
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Tue Sep 26, 2023 5:49 pm
by juergenkulow
Can you post from the file C:\Users\jlcav\AppData\Local\Temp\ccF8Sg8s.s the line 3295 and the previous lines up to and including the line that starts with #?
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Tue Sep 26, 2023 5:51 pm
by JoeC4281
I have updated to PureBasic 6.02 LTS (Windows - x64)
Not comfortable with updating to Beta 6.03 at this time.
When compiling with the C Backend,
the number of errors have been reduced to;
Code: Select all
PureBasic 6.02 LTS - C Backend (Windows - x64)
Loading 'C' subsystem
Compiling ActiveScript.pb
Loading external libraries...
Starting compilation...
Including source: Modul_ActiveScript.pb
1880 lines processed.
Error: Assembler
r:\temp\ccI90jLb.s: Assembler messages:
r:\temp\ccI90jLb.s:2890: Error: invalid character '?' before operand 1
Compiling with the ASM Backend results in successful compilation and execution of program.
Joe
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Tue Sep 26, 2023 10:27 pm
by Olli
@Joe
I can read this message :
juergenkulow wrote:Can you post from the file C:\Users\jlcav\AppData\Local\Temp\ccF8Sg8s.s the line 3295 and the previous lines up to and including the line that starts with #?
I agree this question relates to the version 6.00.
But could even bring the info requested by juergenkulow ?
I observe juergenkulow asks very accurate questions in this domain (in this subject and in a recent subject which is near).
If you, or an other member who has the same problem, you do not give accurate answers to such accurate questions, then your problems will be hardly solvable.
A technical remark I can bring, is the problem is not only for one compiler, but for all compilers (Microsoft as Linux). They have different standards (more than 12, but a main part has open source solves, and, on Microsoft, it is automated by a specific function). So lots of intereting subjects will appear to determine which best converting will be choosen.
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Tue Sep 26, 2023 10:57 pm
by Olli
@fred
On Microsoft, the option mask can be pre-defined.
Ms french doc
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Wed Sep 27, 2023 12:21 am
by JoeC4281
The C:\Users\jlcav\AppData\Local\Temp\ccF8Sg8s.s file does not exist after compilation.
The r:\temp\ccI90jLb.s file does not exist after compilation.
How do I stop the files from being deleted after compilation?
Joe
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Wed Sep 27, 2023 4:41 pm
by juergenkulow
C Backend AT&T Asm cc*.s
Code: Select all
.loc 1 328 12
movl $__S1, %eax
movl $0, 4(%esp)
movl %eax, (%esp)
call ?Command@@YAHPEB_WH@Z
^
ASM Backend FASM
Code: Select all
; Command_("pause", 0)
PUSH dword 0
MOV eax,_S1
PUSH eax
CALL ?Command@@YAHPEB_WH@Z
ADD esp,8
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Thu Sep 28, 2023 1:21 am
by JoeC4281
Using the Take Command Console
Foldermonitor command,
I was able to isolate the problem file.
Code: Select all
r:\temp\ccqAtEwh.s: Assembler messages:
r:\temp\ccqAtEwh.s:2894: Error: invalid character '?' before operand 1
Line 2894 is
call ?Command@@YAHPEB_WH@Z
Code: Select all
R:\hold>type /l r:\hold\ccqAtEwh.s | tail /n+2890
2891 : movq -24(%rbp), %rax
2892 : movl $0, %edx
2893 : movq %rax, %rcx
2894 : call ?Command@@YAHPEB_WH@Z
2895 : movq %rax, -32(%rbp)
2896 : call SYS_PopStringBasePositionUpdate
2897 : movq $0, -8(%rbp)
2898 : nop
2899 : .L158:
2900 : movq -8(%rbp), %rax
Similar to what juergenkulow posted.
Is there a solution for the C Backend?
Again,
everything compiles and works with the Assembler backend,
which is fine with me.
Joe
Notes for my future reference:
Ref: Foldermonitor
https://jpsoft.com/help/foldermonitor.htm
Code: Select all
foldermonitor r:\temp created modified forever copy "r:\temp\%%_folderfile1" "r:\hold"
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Thu Sep 28, 2023 2:32 am
by yuki
JoeC4281 wrote: Thu Sep 28, 2023 1:21 am
Is there a solution for the C Backend?
Again,
everything compiles and works with the Assembler backend,
which is fine with me.
You'd likely get away with loading from the associated DLL directly:
Code: Select all
DeclareModule TakeCmd : EnableExplicit
Declare Command(line.s)
EndDeclareModule
Module TakeCmd : EnableExplicit
; Private types.
; ═══════════════════════════════════════════════════════
PrototypeC _p_libTakeCmd_Command(line.p-unicode, reserved.i)
; Private state.
; ═══════════════════════════════════════════════════════
Global _g_Command._p_libTakeCmd_Command
; Private functions.
; ═══════════════════════════════════════════════════════
Procedure _initLib()
Protected libTakeCmd = OpenLibrary(#PB_Any, "TakeCmd.dll")
If Not libTakeCmd
ProcedureReturn #False
EndIf
_g_Command = GetFunction(libTakeCmd, "?Command@@YAHPEB_WH@Z")
; If you've other functions to load, change to, e.g.:
; _g_Command And _g_AnotherFn And _g_YetAnotherFn ...
; Just make sure all your functions are loaded.
ProcedureReturn _g_Command
EndProcedure
; Public functions.
; ═══════════════════════════════════════════════════════
Procedure Command(line.s)
ProcedureReturn _g_Command(line, #Null)
EndProcedure
; Initialisation.
; ═══════════════════════════════════════════════════════
If Not _initLib()
MessageRequester("Fatal Error:", "Failed to load TakeCmd library.")
End
EndIf
EndModule
TakeCmd::Command("pause")
I've taken the liberty of wrapping it up in a module, which may be handy to contain other helpers for working with the library. You're of course free to forego that and make the prototype and function simply global.
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Thu Sep 28, 2023 6:27 pm
by JoeC4281
Thankyou for that Yuki.
Unfortunately, that will not work.
I did try your method, though, just to confirm.
I use PureBasic to create plugins for Take Command Console,
Ref:
https://jpsoft.com/all-downloads/tcc-plugins.html,
which means I cannot LoadLibrary and GetFunction the TakeCmd.dll,
even from within a plugin.
Ref:
https://www.jpsoft.com/forums/threads/t ... post-62193
If you're trying to load TakeCmd.dll w/o TCMD or TCC that won't work; they both do some required initialization for TakeCmd.dll's internal variables and structures.
Ref:
viewtopic.php?p=575642#p575642
Error when using TakeCmd.lib
Joe
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Thu Sep 28, 2023 7:34 pm
by idle
The problem with the c backend is the import with the mangled name. I don't know how you alias in c but it's passing the import on to as that is causing the problem
Code: Select all
ImportC "takecmd.lib"
Command_(*lpszString, nReserved.i) As "?Command@@YAHPEB_WH@Z"
EndImport
Results in something like this which is valid c but AS goesnt like it.
In c you'd declare the function as extern __cdecl ...
I think it's a bug.
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Thu Sep 28, 2023 7:40 pm
by Olli
juergenkulow wrote: Wed Sep 27, 2023 4:41 pm
C Backend AT&T Asm cc*.s
Code: Select all
.loc 1 328 12
movl $__S1, %eax
movl $0, 4(%esp)
movl %eax, (%esp)
call ?Command@@YAHPEB_WH@Z
^
ASM Backend FASM
Code: Select all
; Command_("pause", 0)
PUSH dword 0
MOV eax,_S1
PUSH eax
CALL ?Command@@YAHPEB_WH@Z
ADD esp,8
Hello juergenkulow,
initially, I thank that joe would answer... But you did it. Thank you for your effort. It seems that it maybe is missing a mangled name converter in the C backend. But... When I read this :
Code: Select all
.loc 1 328 12
movl $__S1, %eax
movl $0, 4(%esp)
movl %eax, (%esp)
call ?Command@@YAHPEB_WH@Z
^
... what is this language ? Source and destination are swapped... ? The shifting address has an other syntax. And the stack is managed in the opposite time (bound before, and positive store index versus bound after and negative store index.
After these strange differences, I think (to be confirmed...) a pre-processing level should be added to convert ms mangled name to single name. I go a little bit too much forward, but maybe a simple trim of '?' character and the suffix should be required if '?'.
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Fri Sep 29, 2023 1:10 am
by yuki
JoeC4281 wrote: Thu Sep 28, 2023 6:27 pm
Thankyou for that Yuki.
Unfortunately, that will not work.
I did try your method, though, just to confirm.
I use PureBasic to create plugins for Take Command Console,
Ref:
https://jpsoft.com/all-downloads/tcc-plugins.html,
which means I cannot LoadLibrary and GetFunction the TakeCmd.dll,
even from within a plugin.
Ah, thanks for the added context, that is handy!
From a DLL, it's generally a bad idea to load other DLLs inside DllMain, which is what the previous example would do when compiled in this way. It also seems like TakeCmd.dll lacks a "?Command@@YAHPEB_WH@Z" and instead exports simply "Command".
I tested the following with TCMD 31 and it seems to work well in both ASM and C-backends, defining a new "thingy" command:
Code: Select all
DeclareModule TakeCmd : EnableExplicit
; Structures.
; ═══════════════════════════════════════════════════════
Structure PluginVersionInfo
major.l
minor.l
build.l
EndStructure
Structure PluginAuthorInfo
name.s
email.s
url.s
EndStructure
Structure PluginInfo
dllName.s
author.PluginAuthorInfo
description.s
functions.s
version.PluginVersionInfo
moduleHandle.i
moduleName.s
EndStructure
; Functions: init.
; ═══════════════════════════════════════════════════════
; Loads TakeCmd library functions. Must be called once at
; startup before executing other functions.
Declare InitializeLibrary()
; Functions: parser.
; ═══════════════════════════════════════════════════════
; Calls the parser to expand and execute the given line.
Declare.l Command(line.s)
; Functions: error handling.
; ═══════════════════════════════════════════════════════
; Beeps.
Declare Honk()
EndDeclareModule
Module TakeCmd : EnableExplicit
; Private types.
; ═══════════════════════════════════════════════════════
Prototype _p_libTakeCmd_Command(line.p-unicode, reserved.i)
Prototype _p_libTakeCmd_honk()
; Private state.
; ═══════════════════════════════════════════════════════
Global _g_Command._p_libTakeCmd_Command
Global _g_honk._p_libTakeCmd_honk
; Public functions: init.
; ═══════════════════════════════════════════════════════
Procedure InitializeLibrary()
Static isInitialised, libTakeCmd
If isInitialised
; Already initialised OK previously. Skip reattempts.
ProcedureReturn #True
ElseIf libTakeCmd
; Already failed initialisation previously. Skip reattempts.
ProcedureReturn #False
EndIf
libTakeCmd = OpenLibrary(#PB_Any, "TakeCmd.dll")
If Not libTakeCmd
ProcedureReturn #False
EndIf
_g_Command = GetFunction(libTakeCmd, "Command")
_g_honk = GetFunction(libTakeCmd, "honk")
isInitialised = Bool(_g_Command And _g_honk)
ProcedureReturn isInitialised
EndProcedure
; Public functions: parser.
; ═══════════════════════════════════════════════════════
Procedure.l Command(line.s)
ProcedureReturn _g_Command(line, #Null)
EndProcedure
; Public functions: error handling.
; ═══════════════════════════════════════════════════════
Procedure Honk()
ProcedureReturn _g_honk()
EndProcedure
EndModule
ProcedureDLL InitializePlugin()
If Not TakeCmd::InitializeLibrary()
MessageRequester("Error:",
"Failed to load <PLUGIN_NAME> plugin!" + #CRLF$ +
"Please try and install the latest version from <AUTHOR_URL> or contact support at <AUTHOR_EMAIL>.",
#PB_MessageRequester_Error)
ProcedureReturn 1
EndIf
ProcedureReturn 0
EndProcedure
ProcedureDLL GetPluginInfo()
Static pluginInfo.TakeCmd::PluginInfo
With pluginInfo
\dllName = "Example"
\description = "Does a thingy."
\functions = "thingy"
\author\name = "Someone"
\author\email = "someone@somewhere.com"
\author\url = "somewhere.com"
\version\major = 1
\version\minor = 0
\version\build = 0
EndWith
ProcedureReturn @pluginInfo
EndProcedure
ProcedureDLL ShutdownPlugin()
ProcedureReturn 0
EndProcedure
ProcedureDLL thingy(*argsRaw.Unicode)
; Take ping params as input, defaulting to "purebasic.com"
Protected pingParams.s = Trim(PeekS(*argsRaw, -1, #PB_Unicode))
If pingParams = ""
pingParams = "purebasic.com"
EndIf
TakeCmd::Honk()
TakeCmd::Command("ping " + pingParams)
TakeCmd::Honk()
TakeCmd::Honk()
ProcedureReturn 0
EndProcedure
This is only a workaround for what looks like a compiler bug. Unless the C-backend is required for your project, I might suggest using simply ASM with your existing working approach for now.
Re: External .LIB compiles with ASM Backend, but not C Backend
Posted: Fri Sep 29, 2023 3:57 pm
by JoeC4281
yuki,
thankyou for taking the time to produce this source code,
which is an alternate method of plugin coding for Take Command Console using PureBasic.
I tried your code, and it works as expected.
Questions.
Using your code, I no longer require the use of;
which means that I no longer require the existence of a
takecmd.lib file for the plugin.
What am I gaining/losing by using your coding method, that is,
OpenLibrary and
GetFunction, versus having to use the takecmd.lib library?
I'm liking the way you coded the plugin, versus the way I have been coding the plugin.
I will do more reading on
DeclareModule/EndDeclareModule and
Module/EndModule, as these are new to me.
Thanks again for your efforts.
Much appreciated.
Joe