NASM: How to resolve these unresolved externals? - linker

I'm trying to get started learning basic assembly with Paul A. Carter's book "PC Assembly Language." However I'm unable to run the first example Carter provides, so I'm kind of stuck until I figure this out.
I assembled the example "first.asm" without any problem, but I can't figure out how to link these files: first.obj, driver.c, asm_io.obj into an executable. In the comment section of first.asm Carter gives these instructions for creating an executable (I'm using Windows 10, VS community 2015 developer command prompt):
; Using MS C/C++
; nasm -f win32 first.asm
; cl first.obj driver.c asm_io.obj
I'm doing exactly that but I'm getting a fatal error 2 unresolved externals, _printf and _scanf. I have every necessary file that I can think of in the same directory, and I'm compiling in that directory.
Driver.c calls the function defined in and it uses a header file called "CDECL.h"; I have this file in my directory, but I don't understand much about this header file. I wonder if the problem is here. I haven't altered it or anything. I assembled asm_io.asm according to Dr. Carter's instructions.
Not too far into asm_io.asm is see this:
extern _scanf, _printf, _getchar, _putchar, _fputs
So here are the unresolved externals. Shouldn't they be defined in stdio.h? Driver.c includes stdio.h, shouldn't the linker be able to resolve these symbols be looking at stdio.h? What might I be missing?
ps. I'm new to programming in general, and this is my first stack overflow question. I'm open to any and all criticism/feedback. I'll provide more information if you need it, I just didn't want to post a massive wall of text and code if not necessary.

Welcome to SO. You need to understand:-
The difference between a header file, e.g.
foo.h // C or maybe C++ header file)
and a library, e.g.
foo.lib foo.dll // Windows
libfoo.a, libfoo.so // Unix/Linux
that implements the calling interface that is (merely) described in a header file.
The difference between compiling or assembling a source file, e.g.
bar.c // C source file
bar.asm // Assembly source, Windows
bar.s // Assembly source, Unix/Linux
to make an object file. e.g.
bar.obj // Windows
bar.o // Unix/Linux
and linking object files and libraries together make a complete executable.
Linking can succeed only if the linker is supplied with (or knows by default)
the names and locations of object files and/or libraries that provide
implementations of all the functions that are called in the program - including
functions whose calling interfaces are described in header files. Otherwise
unresolved symbol errors ensue.
Research these points and you'll quickly get yourself unstuck. See this
pretty good introductory tutorial, which although it is about getting
started with the GNU Compiler Collection rather
than with assembly language programming, will clarify the principles
and distinctions you need to grasp.

Related

C - error: conflicting types for 'SDL_main' [duplicate]

I want to make a game using SDL2, but I'm unable to compile and/or run my code, please help!
SDL2 is notoriously hard to set up, and it's often the first library aspiring game developers try to use.
This post is intended as a canonical duplicate for common problems with setting up SDL2.
This answer is about MinGW / GCC, and not Visual Studio.
This answer only applies to Windows.
Common errors
The common errors are:
SDL.h: No such file or directory (when compiling)
Various SDL_main problems: "undefined reference to SDL_main", "conflicting types for SDL_main" or "number of arguments doesn't match prototype", etc. (when compiling or linking)
undefined reference to other functions (when linking)
DLL problems: (when running your program)
'??.dll' was not found
procedure entry point ... could not be located in ..., and other mysterious DLL-related errors
The program seemingly doing nothing when launched
This list is sorted from bad to good. If you change something and get a different error, use this list to tell if you made things better or worse.
The preamble
0. Don't follow bad advice.
Some resources will suggest you to do #define SDL_MAIN_HANDLED or #undef main. Don't blindly follow that advice, it's not how SDL2 is intended to be used.
If you do everything correcty, it will never be necessary. Learn the intended approach first. Then you can research what exactly that does, and make an educated decision.
1. Figure out how to compile directly from the console, you can start using an IDE and/or build system later.
If you're using an IDE, I suggest to first make sure you're able to compile your program directly from the console, to rule out any IDE configuration problems. After you figure that out, you can use the same compiler options in your IDE.
The same applies to build systems, such as CMake.
2. Download the right SDL2 files. Make sure you have the right files. You need the archive called SDL2-devel-2.0.x-mingw.tar.gz from here.
Extract it to any directory, preferably somewhere near your source code. Extracting into the compiler installation directory is often considered a bad practice (and so is copying them to C:\Windows, which is a horrible idea).
3. Know the difference between compiler flags and linker flags. A "flag" is an option you specify in the command line when building your program. When you use a single command, e.g. g++ foo.cpp -o foo.exe, all your flags are added to the same place (to this single command).
But when you build your program in two steps, e.g.:
g++ foo.cpp -c -o foo.o (compiling)
g++ foo.o -o foo.exe (linking)
you have to know which of the two commands to add a flag to. Those are "compiler flags" and "linker flags" respectively.
Most IDEs will require you to specify compiler and linker flags separately, so even if you use a single command now, it's good to know which flag goes where.
Unless specified otherwise, the order of the flags doesn't matter.
SDL.h: No such file or directory
Or any similar error related to including SDL.h or SDL2/SDL.h.
You need to tell your compiler where to look for SDL.h. It's in the SDL files you've downloaded (see preamble).
Add -Ipath to your compiler flags, where path is the directory where SDL.h is located.
Example: -IC:/Users/HolyBlackCat/Downloads/SDL2-2.0.12/x86_64-w64-mingw32/include/SDL2. Relative paths work too, e.g. -ISDL2-2.0.12/x86_64-w64-mingw32/include/SDL2.
Note that the path will be different depending on how you write the #include:
If you do #include <SDL.h>, then the path should end with .../include/SDL2 (like above). This is the recommended way.
If you do #include <SDL2/SDL.h>, then the path should end with .../include.
Various SDL_main problems
You can get several different errors mentioning SDL_main, such as undefined reference to SDL_main, or conflicting types for 'SDL_main', or number of arguments doesn't match prototype, etc.
You need to have a main function. Your main function must look like int main(int, char **). NOT int main() and NOT void main(). This is a quirk of SDL2, related to it doing #define main SDL_main.
Adding parameter names is allowed (and is mandatory in C), e.g. int main(int argc, char **argv). Also the second parameter can be written as char *[] or with a name: char *argv[]. No other changes are allowed.
If your project has multiple source files, make sure to include SDL.h in the file that defines the main function, even if it doesn't otherwise use SDL directly.
Try to avoid #define SDL_MAIN_HANDLED or #undef main when solving this issue, see preamble for explanation.
undefined reference to various functions
• undefined reference to SDL_...
The error message will mention various SDL_... functions, and/or WinMain. If it mentions SDL_main, consult the section "Various SDL_main problems" above. If the function names don't start with SDL_, consult the section "undefined reference to other functions" below.
You need to add following linker flags: -lmingw32 -lSDL2main -lSDL2 -Lpath, where path is the directory where libSDL2.dll.a and libSDL2main.a (which you've downloaded) are located. The order of the -l... flags matters. They must appear AFTER any .c/.cpp/.o files.
Example: -LC:/Users/HolyBlackCat/Desktop/SDL2-2.0.12/x86_64-w64-mingw32/lib. Relative paths work too, e.g. -LSDL2-2.0.12/x86_64-w64-mingw32/lib.
When you use -l???, the linker will look for a file called lib???.dll.a or lib???.a (and some other variants), which is why we need to pass the location of those files. libmingw32.a (corresponding to -lmingw32) is shipped with your compiler, so it already knows where to find it.
I added all those flags and nothing changed, or I'm getting skipping incompatible X when searching for Y:
You probably use the wrong SDL .a files. The archive you downloaded contains two sets of files: i686-w64-mingw32 (32-bit) and x86_64-w64-mingw32 (64-bit). You must use the files matching your compiler, which can also be either 32-bit or 64-bit.
Print (8*sizeof(void*)) to see if your compiler is 32-bit or 64-bit.
Even if you think you use the right files, try the other ones to be sure.
Some MinGW versions can be switched between 32-bit and 64-bit modes using -m32 and -m64 flags (add them to both compiler and linker flags).
I get undefined reference to a specific function:
• undefined reference to WinMain only
There are several possibilities, all of which were covered in the previous section:
You forgot -lmingw32 and/or -lSDL2main linker flags.
You must use following linker flags, in this exact order, after
any .c/.cpp/.o files: -lmingw32 -lSDL2main -lSDL2
The libSDL2main.a file you use doesn't match your compiler (32-bit file with a 64-bit compiler, or vice versa).
Try to avoid #define SDL_MAIN_HANDLED or #undef main when solving this issue, see preamble for explanation.
• undefined reference to SDL_main only
See the section "Various SDL_main problems" above.
• undefined reference to other functions
Your linker found and used libSDL2.a, but it should be finding and using libSDL2.dll.a. When both are available, it prefers the latter by default, meaning you didn't copy the latter to the directory you passed to -L.
If you intended to perform static linking, see the section called "How do I distribute my app to others?" below.
Nothing happens when I try run my app
Let's say you try to run your app, and nothing happens. Even if you try to print something at the beginning of main(), it's not printed.
Windows has a nasty habit of not showing some DLL-related errors when the program is started from the console.
If you were running your app from the console (or from an IDE), instead try double-clicking the EXE in the explorer. Most probably you'll now see some DLL-related error; then consult one of the next sections.
??.dll was not found
Copy the .dll mentioned in the error message, and place it next to your .exe.
If the DLL is called SDL2.dll, then it's in the SDL files you've downloaded (see preamble). Be aware that there are two different SDL2.dlls: a 32-bit one (in the i686-w64-mingw32 directory), and a 64-bit one (in x86_64-w64-mingw32). Get the right one, if necessary try both.
Any other DLLs will be in your compiler's bin directory (the directory where gcc.exe is located).
You might need to repeat this process 3-4 times, this is normal.
For an automatic way of determining the needed DLLs, see the next section.
procedure entry point ... could not be located in ... and other cryptic DLL errors
Your program needs several .dlls to run, and it found a wrong version of one, left over from some other program you have installed.
It looks for DLLs in several different places, but the directory with the .exe has the most priority.
You should copy all DLLs your program uses (except the system ones) into the directory where your .exe is located.
A reliable way to get a list of needed DLLs is to blindly copy a bunch of DLLs, and then remove the ones that turn out to be unnecessary:
Copy SDL2.dll. It's in the SDL files you've downloaded (see preamble). Be aware that there are two different SDL2.dlls: a 32-bit one (in the i686-w64-mingw32 directory), and a 64-bit one (in x86_64-w64-mingw32). Get the right one, if necessary try both.
Copy all DLLs from your compiler's bin directory (the directory where gcc.exe is located).
Now your program should run, but we're not done yet.
Download NTLDD (or some other program that displays a list of used DLLs). Run ntldd -R your_program.exe.
Any DLL not mentioned in its output should be removed from the current directory. Your program uses everything that remains.
I ended up with following DLLs, expect something similar: SDL2.dll, libgcc_s_seh-1.dll, libstdc++-6.dll (C++ only), libwinpthread-1.dll.
Can I determine the needed DLLs without copying excessive ones?
Yes, but it's less reliable.
Your program searches for DLLs in following locations, in this order:
The directory where your .exe is located.
C:\Windows, including some of its subdirectories.
The directories listed in PATH.
Assuming you (or some jank installer) didn't put any custom DLLs into C:\Windows, adding your compiler's bin directory to the PATH (preferably as the first entry) and either putting SDL2.dll in the same directory as the .exe or into some directory in the PATH should be enough for your program to work.
If this works, you can then run ntldd without copying any DLLs beforehand, and copy only the necessary ones. The reason why you'd want to copy them at all at this point (since your app already works) is to be able to distribute it to others, without them having to install the compiler for its DLLs. Skip any DLLs located outside of your compiler's bin directory (except for SDL2.dll).
Note that the possibility of having weird DLLs in C:\Windows is real. E.g. Wine tends to put OpenAL32.dll into C:\Windows, so if you try this process with OpenAL on Wine, it will fail. If you're making a sciprt that runs ntldd automatically, prefer copying the DLLs (or at least symlinking them - I heard MSYS2 can emulate symlinks on Windows?).
Can I make an EXE that doesn't depend on any DLLs?
It's possible to make an .exe that doesn't depend on any (non-system) .dlls by using the -static linker flag, this is called "static linking". This is rarely done, and you shouldn't need to do this if you did the above steps correctly. This requires some additional linker flags; they are listed in file ??-w64-mingw32/lib/pkgconfig/sdl2.pc shipped with SDL, in the Libs.private section. Notice that there are two files, for x32 and x64 respectively.
How do I distribute my app to others?
Follow the steps in the previous section, titled procedure entry point ... could not be located in ....
A saner alternative?
There is MSYS2.
It has a package manager that lets you download prebuilt libraries, and, as a bonus, a fresh version of the compiler.
Install SDL2 from its package manager. Use a tool called pkg-config (also from the package manager) to automatically determine all necessary flags (pkg-config --cflags SDL2 for compiler flags, pkg-config --libs SDL2 for linker flags).
This is the same experience as you would have on Linux (maybe except for some DLL management hassle).
Bonus - Other problems
Q: My program always opens a console window when I run it, how do I hide it?
A: Add -mwindows to the linker flags.
Q: I get error 'SDL_VideoMode' wasn't declared in this scope.
A: SDL_VideoMode is from SDL1.2, it's not a part of the newer SDL2. Your code was written for the outdated version of SDL. Find a better tutorial that deals specifically with SDL2.
Q: My program has the default file icon, but I want a custom one.
A: Your icon must be in the .ico format. If your graphics editor doesn't support it, make a series of .pngs of common sizes (e.g. 16x16, 32x32, 48x48, 64x64), then convert them to a single .ico using ImageMagick: magick *.png result.ico (or with convert instead of magick).
Create a file with the .rc extension (say, icon.rc), with following contents MyIconName ICON "icon.ico" (where MyIconName is an arbitrary name, and "icon.ico" is the path to the icon). Convert the file to an .o using windres -O res -i icon.rc -o icon.o (the windres program is shipped with your compiler). Specify the resulting .o file when linking, e.g. g++ foo.cpp icon.o -o foo.exe.
Recent versions of SDL2 have a nice property of using the same icon as the window icon, so you don't have to use SDL_SetWindowIcon.
A solution for Visual Studio:
Why not use a package manager? I use vcpkg, and it makes super easy to consume 3rd party libraries. Grab the vcpkg source, and extract it to a safe place, like C:/, then run its bootstrap script bootstrap-vcpkg.bat, this will generate vcpkg executable. Then run vcpkg integrate install to make libraries installed with vcpkg available in Visual Studio.
Search for the library you need:
vcpkg search sdl
imgui[sdl2-binding] Make available SDL2 binding
libwebp[vwebp-sdl] Build the vwebp viewer tool.
magnum[sdl2application] Sdl2Application library
sdl1 1.2.15#12 Simple DirectMedia Layer is a cross-platform development library designed to p...
sdl1-net 1.2.8-3 Networking library for SDL
sdl2 2.0.12-1 Simple DirectMedia Layer is a cross-platform
...
Install it with: vcpkg install sdl2.
Now you just need include SDL2 headers, and everything will work out of the box. The library will be linked automatically.
You can learn more about vcpkg here.
On Mac this is what I follow for XCode (must install g++):
sdl linking:
g++ main.cpp -o main $(sdl2-config --cflags --libs)
XCODE project steps:
open terminal app (macOS)
BUILD SETTINGS (select 'all' and 'combined' search bar enter: "search")
click on "header search paths(way right side click)
add: /usr/local/include
BUILD PHASES --> LINK BINARY LIBRARIES (click plus)
type in SDL --> click "add other"
press: command+SHIFT+g (to bring search bar)
type in: usr/local/Cellar
navigate to: SDL2 -->2.0.8 -->lib --> libSDL2-2.2.0.dylib (make sure not shortcut)

Using C Libraries like OpenGL and LibCurl [duplicate]

This question already has an answer here:
How to Include external C library on windows
(1 answer)
Closed 4 years ago.
I've seen plenty of online tutorials explaining how to use GLFW and libcurl, but where do I actually place the files I downloaded?
For example I downloaded this file for GLFW -
And these are the contents The C+ file wasn't in there I put that there :p
So how would I add the library to any of my .c files?
I've looked everywhere, I might just not be using the right keywords.
And second, how can I have multiple libraries at the same time?
And lastly, what do I put in the <> in the include?
I'm using windows 10 and am using GCC as my compiler. I really should get the Intel one shoudn't I?
This is what the SRC looks like.
In C, a library comes in two parts:
One (or more) header files
The actual library implementation, under Linux either a shared object (.so) or a static library (.a), under Windows I guess it would be a DLL file
You need to include the header file in each C source file of yours where you want to use functionality from the library:
In your source, add a line
#include <library-header.h>
for each header you want to include.
for all header files the library is delivered with.
You will have to tell your compiler where to find the header files. For gcc, you would have to enter something like that on the command line.
gcc -I /path/to/library/directory/include -c my_source.c -o my_source.o
Then, you need to link your program with the actual library. This again, depends on your tool chain, e.g. the compiler you use. For gcc again, the command line would look something like
gcc -lname_of_the_libray -L/path/to/library/directory/ my_source.o -o my_exe
However, libraries are often distributed in source code, which means you would have to compile the library beforehand.

gcc object file linking

I'm learning C by rehashing some Project Euler problems, as I did for Python. In Python, I created a file of general mathematical utilities such as prime number checking, which I pulled functions out of as and when I needed them. I was wondering if there was a way to simply do a similar thing with C, other than compiling alongside the utilities file each time?
I'm running Linux and using gcc as my compiler, if that helps.
It looks like you need some basic knowledge about separate compilation and libraries(archives and shared libraries). You can read about it in chapter "2.3 Writing and Using Libraries" of
Advanced Linux Programming, 1st Edition by CodeSourcery LLC, Mark L. Mitchell, Alex Samuel, Jeffrey Oldham.
This book is also available as a PDF from http://www.advancedlinuxprogramming.com/ (although the site is down at the moment). Perhaps you can search for other places to legally download the PDF.
A crash course:
You create a number of object (*.o) files via
gcc name.c -o name.o
Each file has a header that declares the functions in the source file. You might have several source files using a single header if the functions are related. The source files such as name.c include that header. Your code that uses those functions also includes that header.
You create a static library (archive) with ar
ar ruv libXYZ.a name1.o name2.o ... nameN.o
The prefix lib is important.
You link to the library with
gcc prog.o -lXYZ -o prog
This command will create an executable named prog from the object file prog.o and from object files, extracted from libXYZ.a, which are required to satisfy symbol references from prog.o.

Why do I need to manually link the C runtime library when creating an EXE out of static libraries without any object files?

I'm pretty new to working with libraries and I'm in the process of trying to understand some specifics regarding static libraries and object files.
Summary
The behavior I'm noticing is that I can link several objects to make an executable with no problem, but if I take an intermediate step of combining those objects into static libraries, I cannot link those static libraries to make an executable without additionally specifying the needed C Run-time library in the link command.
Also, or the record, I'm doing the compiling/linking with Visual Studio 2010 from the command line. More details of the process I'm following are below.
First, let's say I have four source files in a project: main.c, util1.c, util2.c, and util3.c.
What works
I can compile these sources with the following command:cl -c main.c util1.c util2.c util3.cAs a result, I now have four object files: main.obj, util1.obj, util2.obj, and util3.obj. These object files each contain a DEFAULTLIB statement intended to inform the linker that it should additionally check the static C Run-time library libcmt.lib for any unresolved external dependencies in these object files when linking them.
I can create an executable named "app_objs.exe" by linking these objects with the following command:
link -out:app_objs.exe main.obj util1.obj util2.obj util3.obj
As mentioned in step 1, the linker used the runtime library due to the compiler's step of adding a default library statement to the objects.
Where I'm confused
Let's say I want to have an intermediate step of combining these objects into static libraries, and then linking those resulting LIB files to create my executable. First, I can create these libraries with the following commands:
link -lib -out:main.lib main.obj
link -lib -out:util.lib util1.obj util2.obj util3.obj
Now, my original thought was that I could simply link these libraries and have the same executable that I created in step 2 of "What works". I tried the following command and received linker error LNK1561, which states that an entry point needs to be specified:
link -out:app_libs.exe main.lib util.lib
From Microsoft's documentation, it is evident that linking libraries without any object files may require entry points to be specified, so I modified the command to set the subsystem as "console" to specify that the executable in intended to be a console application (which seems to imply certain entry points, thereby resolving that error):link -out:app_libs.exe -subsystem:console main.lib util.libUnfortunately, now I get a linker error stating that mainCRTStartup is an unresolved external symbol. I understand that this is defined in the C runtime library, so I can resolve this issue by manually specifying that I want to link against libcmt.lib, and this gives me a functioning executable:link -out:app_libs.exe -subsystem:console main.lib util.lib libcmt.lib
What I'm not understanding is why the default library info that the compiler placed in each object file couldn't be used to resolve the dependency on libcmt.lib. If I can link object files without explicitly stating I want libcmt.lib, and I created static libraries that are containers for the object files, why can't I link those static libraries without having to explicitly state that I want libcmt.lib? Is this just the way things are, or is there some way I could create the static libraries so that the linker will know to check for unresolved symbols in the runtime library?
Thanks for your help. If I have some fundamentally incorrect ideas here, I'd love suggestions on good references to learn all of this correctly.
Well the answer to your misunderstanding is that .lib files are often a product in themselves, and the compiler can't make those assumptions safely. That's what "external" is for.
If I produce binaries for someone's platform because its users are totally helpless, and they want/need static linkage, I have to give them foo.h and libfoo.lib without tying them to a specific runtime entry point. They may very well have defined their own entry point already for their final product, whether DLL or EXE.
You either want the runtime, or you want your own .obj that contains your entry point. Be warned that declaring and defining mainCRTStartup on your own may mean you're not executing important instructions for the target platform.

Compaq Visual Fortran - Crashes During Linking A .LIB File

When I compile with Compaq Visual Fortran, I get these errors (when it starts the linker process) that should be located in a .lib file I thought I added to the workspace:
X30XFULL.OBJ : error LNK2001: unresolved external symbol _BCON#4
X30XFULL.OBJ : error LNK2001: unresolved external symbol _RCON#16
According to where I've googled about, it looks like Compaq Visual Fortran (Version 6, FYI) can't find the library files...
My main question is, how do I use them? Could there possibly be other missing files? Here is what I've tried:
Right Click->Adding the files in the FileView window
Going under Project->Settings, Clicking the Link tab, and under the input category, adding the library files under object/library modules (bprop.lib rprop.lib) and having the Additional Library Path point to where the files are. I also did this under the Resources tab and where it says "Additional Resource Include Directories," I put the directory of where these files were located.
To cover my bases, I also put these files in where the project workspace file, where the compiled executable file would be generated, and pretty much any place I could think of that CVF might possibly look to in order to find these files.
A little background:
I have this Fortran executable that was last compiled in the 90s. From my research, it's a 16-bit compiled one which won't work on a 64-bit machine.
The original code has, at least from what we can gather, 16 bit compiled libraries. Without the original compiler, we can't figure out how to look at or use them. We also have a (semi)equivalent library file that's actually a .FOR file. For all we know, the BPROP.FOR and BPROP.LIB could be the same file (they were found in the same source code area). If we use the BPROP.FOR file, the program can compile, but we are having issues with results that we've traced down to information that is used/gathered/processed in that file.
However, we do have 32-bit versions of (what we think) are the same .lib files. So, we're trying to use that, which is what is being used to compile the Fortran executable which results in the errors above.
Found the answer, at least for me. I don't know how easy it'll be to extrapolate if anyone else finds these answers, but this is how I solved it.
With the old Fortran libraries, all I had to do was add them to the FileList view that has all of the different fortran files (.FOR, etc). I did not have to add these libraries in the settings like I mentioned, but that will work as well. Other then that, I didn't need to add any extra declarations or anything similar.
What we did find out is that the function in question (BCON and RCON) that calls those .LIB files required an additional argument. The only way I found this out was examining other source code that used those libaries, so if anyone is stuck like I was, that would be a good place to start. Alternatively, if you can read the .lib file in a hex editor, you can kind of make out functions and their arguments.
Of course, if you have the original source code for said arguments, that's even better. :)

Resources