I am trying to compile a hello world on windows with the ML and LINK that ship with VS 2010.
.MODEL FLAT
.STACK 4096
.data
msg db "Hello World!",0
.code
INCLUDELIB MSVCRT
EXTRN printf:NEAR
EXTRN exit:NEAR
PUBLIC _main
_main PROC
mov eax, offset msg
push eax
call printf
mov eax,0
push eax
call exit
_main ENDP
END _main
I keep getting linker errors saying that printf and exit are unresolved external symbols. I have a couple of questions.
What are the command line options to use with ML and LINK to compile and resolve the error messages.
Is there another way to display text output to the screen using assembly code rather than calling c runtime functions like printf?
You need to use underscored names for C functions, since that's how the compiler emits them on assembly
level.
You should clean up the stack after calling printf and other CRT functions, since they use cdecl calling convention (caller stack cleanup). Strictly speaking you should do it after _exit too, but that's less important since it never returns.
To use CRT functions you have to initialize CRT. You can check how it's done in the file VC\crt\src\crt0.c
Here's a minimal file that worked for me (I used static library because I have VS2008 and didn't want to fiddle with manifests to make it work with DLL).
.386
.MODEL FLAT
.STACK 4096
.data
msg db "Hello World!",0
.code
INCLUDELIB LIBCMT
EXTRN _printf:NEAR
EXTRN _exit:NEAR
EXTRN __heap_init:NEAR
EXTRN __mtinit:NEAR
EXTRN __ioinit:NEAR
PUBLIC _main
_main PROC
push 1
call __heap_init
add esp, 4
push 1
call __mtinit
add esp, 4
call __ioinit
mov eax, offset msg
push eax
call _printf
pop ecx
mov eax,0
push eax
call _exit
_main ENDP
END _main
For MSVCRT the initialization is different, e.g. you need to call set_app_type
To not rely on CRT, you have to use the OS APIs. In case of Win32 that would be Win32 functions such as WriteFile (with GetStdHandle(STD_OUTPUT_HANDLE) for the file handle). See some examples here.
Related
Please check my short code below.
pwrapper.h
#include <stdio.h>
#include <stdarg.h>
extern"C" int mm_printfA(const char *fmt, ...);
extern"C" int mm_printfW(const wchar_t *fmt, ...);
pwrapper.cpp
#include "pwrapper.h"
int mm_printfA(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int ret = vprintf(fmt, args);
va_end(args);
return ret;
}
int mm_printfW(const wchar_t *fmt, ...)
{
va_list args;
va_start(args, fmt);
int ret = vwprintf(fmt, args);
va_end(args);
return ret;
}
main.cpp
#include "pwrapper.h"
// cl /MT /D _NO_CRT_STDIO_INLINE main.cpp pwrapper.cpp
void main()
{
mm_printfA("What is %d?\n", 123);
}
#if 0
void usedull()
{
vprintf(NULL, NULL);
vwprintf(NULL, NULL);
}
#endif
For some reason, I need to compile it with _NO_CRT_STDIO_INLINE, like this:
cl /MT /D _NO_CRT_STDIO_INLINE main.cpp pwrapper.cpp
But link stage fails saying unresolved external symbol vwprintf and vprintf .
A very weird workaround I find out is: Enable the usedull() function body -- although never be called, and, link through pwrapper.lib, using bb.bat below:
#setlocal EnableDelayedExpansion
#set CFLAGS=/D _NO_CRT_STDIO_INLINE
cl /nologo /c /MT %CFLAGS% pwrapper.cpp
#if errorlevel 1 exit /b 4
lib /nologo /out:pwrapper.lib pwrapper.obj
#if errorlevel 1 exit /b 4
cl /nologo /c /MT main.cpp
#if errorlevel 1 exit /b 4
link /nologo main.obj pwrapper.lib
#if errorlevel 1 exit /b 4
Well, this really works, but why?
This is not a pleasant workaround, because each exe project needs to include a "useless" usedull() function. So, is there any better way?
I really can't tell why this workaround works, an explanation of it is very welcome.
==== Some Clarification ====
There were two main.cpp in my original post. Let me name them separately for later reference in case someone would bother to answer this weird question.
main.0.cpp refers to the one without usedull().
main.1.cpp refers to the one with usedull().
In this question, I use VC++ headers and libs for application(not for kernel), and
I compile main.0.cpp and main.1.cpp without _NO_CRT_STDIO_INLINE.
I always compile pwrapper.cpp with _NO_CRT_STDIO_INLINE.
Whether having pwrapper.obj go through pwrapper.lib produce the same result in this issue.
In short:
compiling pwrapper.cpp with -D _NO_CRT_STDIO_INLINE tells the compiler you are going to provide your own implementation of vprintf and vwprintf at link time, and
compiling main.cpp without -D _NO_CRT_STDIO_INLINE tells the compiler to include implementations of vprintf and vwprintf which are used at link time to satisfy both the references from usedull and mm_printfA/mm_printfW
so, this particular combination works to resolve all undefined symbols at link time. See below for more discussion however.
Discussion
In stdio.h, vprintf (which I'll focus on, but vwprintf is configured in the same way) is defined like so:
_Check_return_opt_
_CRT_STDIO_INLINE int __CRTDECL vprintf(
_In_z_ _Printf_format_string_ char const* const _Format,
va_list _ArgList
)
#if defined _NO_CRT_STDIO_INLINE
;
#else
{
return _vfprintf_l(stdout, _Format, NULL, _ArgList);
}
#endif
Note that
if _NO_CRT_STDIO_INLINE is defined, this becomes a forward declaration
whereas if it is not defined, the full body is included in the compilation of the including translation unit.
Additionally, in corecrt_stdio_config.h whether _NO_CRT_STDIO_INLINE is defined determines the value of _CRT_STDIO_INLINE; if it is defined, _CRT_STDIO_INLINE is defined as empty, otherwise it is defined as __inline.
Putting these together,
if _NO_CRT_STDIO_INLINE is not defined, these functions will be candidates for inline expansion,
otherwise a separate implementation of that function will need to be provided at link time.
Default Compilation (no /O1, /O2, no _NO_CRT_STDIO_INLINE)
The above works with the specific compile and link invocations you are using, as without optimization the compiler will simply include the function body in the compilation of main.1.obj. You can see this using dumpbin; running dumpbin -symbols main.1.obj | find "| vprintf" prints:
01D 00000000 SECT8 notype () External | vprintf
showing that main.1.obj provides vprintf as an externally available symbol.
Checking pwrapper.obj, we get:
00A 00000000 UNDEF notype () External | vprintf
showing that vprintf is undefined in this object file, and will need to be provided at link time.
Optimisation for Inline Expansion
However, if we change the optimisation option for inline expansion, we get different results. Using even the first level of optimisation (-Ob1, included in -O1 and -O2) like so:
cl -c -Ob1 main.1.cpp
causes the compiler to incorporate the body of vprintf directly into usedull, and remove the separate implementation of vprintf, which can be confirmed using dumpbin. So, as you would now expect, attempting to link main.1.obj and pwrapper.obj together will once again give your original error:
pwrapper.obj : error LNK2019: unresolved external symbol vwprintf referenced in function mm_printfW
pwrapper.obj : error LNK2019: unresolved external symbol vprintf referenced in function mm_printfA
main.exe : fatal error LNK1120: 2 unresolved externals
Multiple Implementations?
So, following on from that it is apparent that compiling both files with -D _NO_CRT_STDIO_INLINE will fail as there will be no implementations of the relevant methods. What about if both are compiled without this definition?
If we check the object files, both have defined symbols for vprintf:
01D 00000000 SECT8 notype () External | vprintf
and:
01A 00000000 SECT7 notype () External | vprintf
which under normal circumstances would result in errors due both to multiple definitions of a symbol and violations of the One Definition Rule. However, when performing inline expansion, the compiler and linker have your back. As per 2:
Rather than expand an inline function defined in a header file, the compiler may create it as a callable function in more than one translation unit. The compiler marks the generated function for the linker to prevent one-definition-rule (ODR) violations.
Two IDL files, testbase.idl
module Test{
enum JobType{
TYPE1,
TYPE2,
TYPE3
};
struct UserContext{
string name;
string ssoToken;
};
};
testhello.idl:
#include "testbase.idl"
module Test
{
interface Hello
{
void createJob(in UserContext type);
};
};
and Hello.mpc content is:
project(testbaseIDL): taoidldefaults, anytypecode {
idlflags += -Wb,stub_export_macro=TEST_BASE_STUB_Export -Wb,stub_export_include=test_base_stub_export.h -Wb,skel_export_macro=TEST_BASE_SKEL_Export -Wb,skel_export_include=test_base_skel_export.h
IDL_Files {
testhello.idl
}
custom_only = 1
}
project(testhelloIDL): taoidldefaults, anytypecode {
idlflags += -Wb,stub_export_macro=TEST_HELLO_STUB_Export -Wb,stub_export_include=test_hello_stub_export.h -Wb,skel_export_macro=TEST_HELLO_SKEL_Export -Wb,skel_export_include=test_hello_skel_export.h
IDL_Files {
testhello.idl
}
custom_only = 1
}
project(test_base_server): naming, iortable, utils, avoids_corba_e_micro, anytypecode {
sharedname = test_base_server
after += *IDL
Source_Files {
testbaseS.cpp
}
Header_Files{
testbaseS.h
testbaseC.h
test_base_skel_export.h
}
dynamicflags += TEST_BASE_SKEL_BUILD_DLL TEST_BASE_STUB_BUILD_DLL
}
project(test_base_client): naming, iortable, utils,anytypecode {
sharedname = test_base_client
dynamicflags += TEST_BASE_STUB_BUILD_DLL
Source_Files {
testbaseC.cpp
}
Header_Files{
test_base_stub_export.h
testbaseC.h
}
}
project(testhelloserver): naming, iortable, utils, avoids_corba_e_micro,anytypecode {
sharedname = test_hello_server
dynamicflags += TEST_HELLO_SKEL_BUILD_DLL
libs += test_base_server test_hello_client test_base_client
Source_Files {
testhelloS.cpp
}
Header_Files{
testhelloS.h
testbaseS.h
test_hello_skel_export.h
}
}
project(testhelloclient): naming, iortable, utils,anytypecode {
sharedname = test_hello_client
dynamicflags += TEST_HELLO_STUB_BUILD_DLL
libs += test_base_client
Source_Files {
testhelloC.cpp
}
Header_Files{
testhelloC.h
testbaseC.h
test_hello_stub_export.h
}
}
I want to do some demo. The mpc would generate 4 main projects(testbaseClient, testbaseserver, testhelloServer and testhelloClient) and each projects would generate one dll and library and all of them are used as skeleton and stub for each IDL.
In VS2008, after building testUDL, testbaseclient, testbaseServer, the links for both testbaseserver and testbaseclient fail because link can not find some symbols. The error messages are:
1>testhelloC.obj : error LNK2019: unresolved external symbol "bool __cdecl operator::marshal(class TAO_OutputCDR &)" (?marshal#?$In_Var_Size_Argument_T#UUserContext#Test##VAny_Insert_Policy_Stream#TAO###TAO##UAE_NAAVTAO_OutputCDR###Z)
1>testhelloC.obj : error LNK2019: unresolved external symbol "void __cdecl operator::any_insert(class CORBA::Any *,struct Test::UserContext const &)" (?any_insert#?$Any_Insert_Policy_Stream#UUserContext#Test###TAO##SAXPAVAny#CORBA##ABUUserContext#Test###Z)
1>testhelloS.obj : error LNK2001: unresolved external symbol "void __cdecl operatortesthelloS.obj : error LNK2019: unresolved external symbol "bool __cdecl operator>>(class TAO_InputCDR &,struct Test::UserContext &)" (??5#YA_NAAVTAO_InputCDR##AAUUserContext#Test###Z) referenced in function "public: virtual bool __thiscall TAO::In_Var_Size_SArgument_T::demarshal(class TAO_InputCDR &)" (?demarshal#?$In_Var_Size_SArgument_T#UUserContext#Test##VAny_Insert_Policy_Stream#TAO###TAO##UAE_NAAVTAO_InputCDR###Z)
1>.\test_hello_serverd.dll : fatal error LNK1120: 3 unresolved externals
I understand the error: unresolved external symbol happens only if link could not find those symbol from itself or dependent libraries. Therefore, I added
libs += test_base_server test_base_client
for both testhelloclient and testhelloserver. After regenerating all project, the result is the same. The "unresolved external symbol" still there.
I suspect the two generated base library are wrong and I use command:
dumpbin /EXPORTS
to export all symbol and none reported unresolved external symbol are there.
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file test_base_clientd.dll
File Type: DLL
Section contains the following exports for test_base_clientd.dll
00000000 characteristics
526C30F9 time date stamp Sat Oct 26 18:15:37 2013
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00003130 ??4_Init_locks#std##QAEAAV01#ABV01##Z = ??4_Init_locks#std##QAEAAV01#ABV01##Z (public: class std::_Init_locks & __thiscall std::_Init_locks::operator=(class std::_Init_locks const &))
Summary
1000 .data
2000 .idata
3000 .rdata
1000 .reloc
1000 .rsrc
9000 .text
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file test_base_serverd.dll
File Type: DLL
Section contains the following exports for test_base_serverd.dll
00000000 characteristics
526C2AEE time date stamp Sat Oct 26 17:49:50 2013
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00003130 ??4_Init_locks#std##QAEAAV01#ABV01##Z = ??4_Init_locks#std##QAEAAV01#ABV01##Z (public: class std::_Init_locks & __thiscall std::_Init_locks::operator=(class std::_Init_locks const &))
Summary
1000 .data
2000 .idata
3000 .rdata
1000 .reloc
1000 .rsrc
9000 .text
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file test_base_serverd.lib
File Type: LIBRARY
Exports
ordinal name
??4_Init_locks#std##QAEAAV01#ABV01##Z (public: class std::_Init_locks & __thiscall std::_Init_locks::operator=(class std::_Init_locks const &))
Summary
E1 .debug$S
14 .idata$2
14 .idata$3
4 .idata$4
4 .idata$5
16 .idata$6
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file test_base_clientd.lib
File Type: LIBRARY
Exports
ordinal name
??4_Init_locks#std##QAEAAV01#ABV01##Z (public: class std::_Init_locks & __thiscall std::_Init_locks::operator=(class std::_Init_locks const &))
Summary
E1 .debug$S
14 .idata$2
14 .idata$3
4 .idata$4
4 .idata$5
16 .idata$6
Then what I am confused is that:
1) Would link requires all symbol available during making library project. What my past experience in unix is that all symbol is required only if it is on making executable file.
2) How to resolve this issue here? Should I add some arguments for testIDL projects?
[UPdate]:
Added all *C.cpp for testhelloclient and all *C.cpp and *S.cpp would make compilation work.
However, this is not as I expected. I want to compile each IDL into two libraries: one is for stub and another is for skeleton. Then in the future, I only need to deliver stub/skeleton with corresponding header files for other projects. It is unnecessary for skeleton/sub application to compile any of cpp files generated by IDL when .lib/.dll and header file is available.
Currently, none of *.lib files generated above contain symbol from *C.cpp or *S.cpp(the dumpbin result is similar as post previous, only 1 function). And other application would still report unresolve symbols because .lib does not contain any export symbols.
I read MSDN: http://msdn.microsoft.com/en-us/library/ms235636%28v=vs.90%29.aspx this afternoon. For export symbol of dll, the function is declared as:
static __declspec(dllexport) double Add(double a, double b);
but idl generated c header files seems not follow this way..
VC seems much different with GCC in Linux. Is there some solution?It is impossible for I to add _declsepc for each functions in IDL generated header files? The issue is simplified as: none of symbols is export in library generated from IDL in VC(I renamed title for more clarification)
[More update]
I go back to the tao_idl command, it seems it is caused by options like: -Wb,skeleton_export_include="headerfile.h" export_macro..
It seems all these files and macros are generated....Is there any better to gernated .mpc file and are these headerfile.h and macros?
[UPDATE]
It now works with updated mpc file(see above). The export files are generated by generate_export_file.pl which is in $ACE_ROOT/bin directory. The command is like:
generate_export_file.pl TEST_HELLO_STUB > test_hello_stub_export.h
Thanks all.
You have to add anytypecode also as base project in the other projects in the IDL file, not only with the IDL file itself. Also just use naming instead of namingexe, you only need to use the naming service stubs, not the full service implementation
I'm developing a dynamic library for an iOS application(not for apple store). Given an IPA, to what extent my dynamic library can be decompressed by hacker/user? can my method definitions in dynamic library read while decompressing? Thanks in advance.
From man dyldinfo:
dyldinfo(1) BSD General Commands Manual dyldinfo(1)
NAME
dyldinfo -- Displays information used by dyld in an executable
SYNOPSIS
dyldinfo [-arch arch-name] [-dylibs] [-rebase] [-bind] [-weak_bind] [-lazy_bind] [-export] [-opcodes]
[-function_starts] file(s)
DESCRIPTION
Executables built for Mac OS X 10.6 and later have a new format for the information in the __LINKEDIT
segment. The dyldinfo tool will display that information.
The options are as follows:
-arch arch
Only display the specified architecture. Other architectures in a universal image are ignored.
-dylibs
Display the table of dylibs on which this image depends.
-rebase
Display the table of rebasing information. Rebasing is what dyld does when an image is not
loaded at its preferred address. Typically, this involves updating pointers in the __DATA seg-
ment which point within the image.
-bind Display the table of binding information. These are the symbolic fix ups that dyld must do
when an image is loaded.
-weak_bind
Display the table of weak binding information. Typically, only C++ progams will have any weak
binding. These are symbols which dyld must unique accross all images.
-lazy_bind
Display the table of lazy binding information. These are symbols which dyld delays binding
until they are first used. Lazy binding is automatically used for all function calls to func-
tions in some external dylib.
-export
Display the table symbols which this image exports.
-opcodes
Display the low level opcodes used to encode all rebase and binding information.
-function_starts
Decodes the list of function start addresses.
This is just one example of the tools that can be used for analysis of dylibs. On my machine, for instance, I ran it on one of OpenSceneGraph's dylibs and here is a snippet I got:
0x143942 __ZN3osg13gluDeleteTessEPNS_13GLUtesselatorE
0x143968 __ZL9GotoStatePN3osg13GLUtesselatorE9TessState
0x143AA9 __ZN3osg15gluTessPropertyEPNS_13GLUtesselatorEjd
0x143B75 __ZN3osg18gluGetTessPropertyEPNS_13GLUtesselatorEjPd
0x143C70 __ZN3osg13gluTessNormalEPNS_13GLUtesselatorEddd
0x143C85 __ZN3osg15gluTessCallbackEPNS_13GLUtesselatorEjPFvvE
0x143E44 __ZN3osg13gluTessVertexEPNS_13GLUtesselatorEPdPv
0x143FE4 __ZL10EmptyCachePN3osg13GLUtesselatorE
0x144063 __ZL9AddVertexPN3osg13GLUtesselatorEPdPv
0x14411A __ZN3osg19gluTessBeginPolygonEPNS_13GLUtesselatorEPv
0x144161 __ZN3osg19gluTessBeginContourEPNS_13GLUtesselatorE
0x1441A1 __ZN3osg17gluTessEndContourEPNS_13GLUtesselatorE
0x1441C9 __ZN3osg17gluTessEndPolygonEPNS_13GLUtesselatorE
And:
__DATA __const 0x001D9D28 pointer 0 __ZTv0_n72_NK3osg6Camera12DrawCallback9classNameEv
__DATA __data 0x001E8208 pointer 0 __ZTv0_n72_NK3osg6Camera12DrawCallback9classNameEv
__DATA __data 0x001E84E8 pointer 0 __ZTv0_n72_NK3osg6Camera12DrawCallback9classNameEv
__DATA __const 0x001DA5F8 pointer 0 __ZTv0_n72_NK3osg8Drawable12CullCallback9classNameEv
__DATA __data 0x001E57E8 pointer 0 __ZTv0_n72_NK3osg8Drawable12CullCallback9classNameEv
And like always, pulling out strings and other const data is ridiculously easy. (The following is from a .so ... I couldn't find an x86 dylib on my system in my 30 seconds of searching ... the method is the same, though) (oh and you can tell that I disasm'd a library shipped with valgrind):
If you have strings consisting of sensitive data then those can easily be pulled from your libs... this is what I got from just dropping one lib into IDA:
__cstring:00003A58 ; Segment type: Pure data
__cstring:00003A58 __cstring segment dword public 'DATA' use32
__cstring:00003A58 assume cs:__cstring
__cstring:00003A58 ;org 3A58h
__cstring:00003A58 aDevRandom db '/dev/random',0 ; DATA XREF: _vgr00000ZU_libSystemZdZaZddylib_arc4random+17o
__cstring:00003A58 ; __data:__crashreporter_info__o
__cstring:00003A64 aValgrind_launc db 'VALGRIND_LAUNCHER',0 ; DATA XREF: vg_cleanup_env+1Co
__cstring:00003A76 aDyld_shared_re db 'DYLD_SHARED_REGION',0
__cstring:00003A89 aDyld_insert_li db 'DYLD_INSERT_LIBRARIES',0
__cstring:00003A9F align 10h
__cstring:00003AA0 aInstrumentedBy db 'Instrumented by Valgrind 3.8.1',0
__cstring:00003AA0 __cstring ends
This is where you'd find all the const strings that are used. Below this section (not shown) is the "pure data" section where other const data is stored.
So, again, it totally depends on exactly what information is sensitive.
I've just stumbled across this and I'm a bit puzzled.
I have an out-of-the-box VS 2010 F# project, with all default settings, targeting .NET 4.0.
The F# code is like this:
let test(a:int, b:int, c:int) = min a (min b c)
When I compile it for release, the generated IL contains some strange NOP
instructions scattered around. Like this:
The generated IL for this (with all default settings):
.method public static int32 test(int32 a,
int32 b,
int32 c) cil managed
{
// Code size 20 (0x14)
.maxstack 4
.locals init ([0] int32 V_0)
// HERE
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: bge.s IL_0009
IL_0005: ldarg.1
// HERE
IL_0006: nop
IL_0007: br.s IL_000b
IL_0009: ldarg.2
// HERE
IL_000a: nop
IL_000b: stloc.0
IL_000c: ldarg.0
IL_000d: ldloc.0
IL_000e: bge.s IL_0012
IL_0010: ldarg.0
IL_0011: ret
IL_0012: ldloc.0
IL_0013: ret
} // end of method Module1::test
My .fsproj project configuration is:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<Tailcalls>true</Tailcalls>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<WarningLevel>3</WarningLevel>
<DocumentationFile>bin\Release\TestFsIL.XML</DocumentationFile>
</PropertyGroup>
Now, if I comment out line <DebugType>pdbonly</DebugType>, the NOP instructions
disappear. But of course so does the PDB file!
.method public static int32 test(int32 a,
int32 b,
int32 c) cil managed
{
// Code size 17 (0x11)
.maxstack 4
.locals init (int32 V_0)
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: bge.s IL_0007
IL_0004: ldarg.1
IL_0005: br.s IL_0008
IL_0007: ldarg.2
IL_0008: stloc.0
IL_0009: ldarg.0
IL_000a: ldloc.0
IL_000b: bge.s IL_000f
IL_000d: ldarg.0
IL_000e: ret
IL_000f: ldloc.0
IL_0010: ret
} // end of method Module1::test
There is also a subtle different in the .locals line:
.locals init ([0] int32 V_0)
vs
.locals init (int32 V_0)
When I tried C# compiler, it generates NOP instructions only in the
debug builds, but these seem to go away in release builds, even when
PDB files are included using <DebugType>pdbonly</DebugType>.
Questions:
Why are NOP instructions generated in F# in release build when PDB files are included, when C# seems to be able to avoid this.
Is there any way to get rid of those NOP, but still have the PDB files?
PS. There are related questions on SO here
and here,
but all the answers there say
you are compiling in debug mode, if you compile in release mode, the NOP goes away
which contradicts my experience with F# compiler as demonstrated.
I don't exactly know how this works internally in the F# compiler (somebody from the F# team may have a better answer), but my guess is that generating nop instructions is just a fairly easy way to generate locations that can be referred to from the pdb file.
The pdb file needs to specify some IL range for expression in the code where you can place a breakpoint - and this is the case in both Debug and Release mode. This means that if you place a breakpoint somewhere, there needs to be a corresponding location in the IL. However, if there is no actual instruction, corresponding to the source code location, the compiler needs to insert something - so it adds nop.
In Release mode, the F# compiler does more optimizations, but if you want pdb files, it still needs to provide location for all source code locations. This might not be needed in C#, because C# maps more closely to the source IL, but it might be harder to avoid this in F#.
I have the following trivial Lua program which I copied from the book Programming In Lua
#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int main (void)
{
char buff[256];
int error;
lua_State *L = luaL_newstate(); /* opens Lua */
luaL_openlibs(L); /* opens the standard libraries */
while (fgets(buff, sizeof(buff), stdin) != NULL)
{
error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
lua_pcall(L, 0, 0, 0);
if (error)
{
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop(L, 1); /* pop error message from the stack */
}
}
lua_close(L);
return 0;
}
my environment is cywin
my make file looks like this:
CC=gcc
INCLUDE='-I/home/xyz/c_drive/Program Files/Lua/5.1/include'
LINKFLAGS='-L/home/xyz/c_drive/Program Files/Lua/5.1/lib' -llua51
li.o:li.c
$(CC) $(INCLUDE) -c li.c
main:li.o
$(CC) -o main $(LINKFLAGS) li.o
clean:
rm *.o
rm main
My /home/xyz/c_drive/Program Files/Lua/5.1/lib directory contains lua5.1.dll lua5.1.lib lua51.dll and lua51.lib
Trying to build my main target I am getting the following errors:
li.o:li.c:(.text+0x35): undefined reference to `_luaL_newstate'
li.o:li.c:(.text+0x49): undefined reference to `_luaL_openlibs'
li.o:li.c:(.text+0xaf): undefined reference to `_luaL_loadbuffer'
li.o:li.c:(.text+0xd9): undefined reference to `_lua_pcall'
li.o:li.c:(.text+0x120): undefined reference to `_lua_tolstring'
li.o:li.c:(.text+0x154): undefined reference to `_lua_settop'
li.o:li.c:(.text+0x167): undefined reference to `_lua_close'
Any ideas about what I might be doing wrong here?
The problem is that you have named the libraries on the link command line before the object files that require them. The linker loads modules from left to right on the command line. At the point on the line where you name -llua51, no undefined symbols that could be satisfied by that library are known. Then you name li.o, which does have unknown symbols.
Some Unix-like environments don't treat this as an error because part of the link process is deferred to the program load when reference to .so files are satisfied. But Cygwin, MinGW, and Windows in general must treat this as an error because DLLs work quite differently from .so files.
The solution is to put -llua51 after all the .o files on your link line.
Edit: Incidentally, it appears you are linking against the Lua for Windows distribution, but building with GCC under Cygwin. You will want to use Dependency Walker to make sure that your program does not depend on the Cygwin runtime, and that it does depend on the same C runtime as the lua51.dll from Lua for Windows. IIRC, that will be the runtime for the previous version of Visual Studio. It is possible to make GCC link against that, but you will need to be using the MinGW port (which you can use from Cygwin), and link against a couple of specific libraries to get that version. I'm away from my usual PC, or I'd quote an exact link line. (I believe you need -lmoldname -lmsvcr80 or something like that, as the last items on the link line.)
It will cause mysterious and very hard to diagnose problems if more than one C runtime library is in use. The easy answer is to use the same one as your preferred Lua DLL. Another alternative is that the Lua Binaries project has pre-compiled Lua DLLs for a wide array of C toolchains on Windows. If you need a Lua application that understands the Cygwin environment, you will want one that is built by GCC for Cygwin and not the Lua for Windows flavor. Lua Binaries will be your friend, or you can build Lua your self from source.
The names in the Lua API do not have those leading underscores. Try compiling with -fno-leading-underscore.