DEV Community

So
So

Posted on • Edited on

Building Windows DLLs With GCC

Introduction

Compiling C (and C++) code in Windows is simple, as all we need is to create a barebones project with everything we need using Visual Studio. But Visual studio and VS code uses telemetry to track usage data. Simply put, VS Code and Visual Studio are spywares. Therefore, in the spirit of OpSec, we can use an alternative compiler that does not spy on code in development.

GCC is an open-source optimizing compiler produced by the GNU Project supporting various programming languages, hardware architectures and operating systems. It is distributed as MinGW and Cygwin for Windows.

This article will show you the basics of creating a DLL for a calculator application and dynamically linking (implicitly) to them in your applications with GCC under MingGW. You can download MinGW from https://sourceforge.net/projects/mingw-w64/

Step 1

We will declare and export our basic function in a header file: calcdll.h

/* calcdll.h

   Declares the functions to be imported by our application, and exported by our
   DLL.
*/

#ifdef CALCDLL_EXPORTS /*  define ADD_EXPORTS *only* when building the DLL. */
  #define CALCDLL_API __declspec(dllexport)
#else
  #define CALCDLL_API __declspec(dllimport)
#endif

/* Define calling convention in one place, for convenience. */
#define CALL __cdecl

/* Make sure functions are exported with C linkage under C++ compilers. */

#ifdef __cplusplus
extern "C"
{
#endif

/* Declare our Add function using the above definitions. */
CALCDLL_API int CALL Add(int a, int b);
CALCDLL_API int CALL Subtract(int a, int b);
CALCDLL_API int CALL Divide(int a, int b);
CALCDLL_API int CALL Multiply(int a, int b);

#ifdef __cplusplus
} // __cplusplus defined.
#endif
Enter fullscreen mode Exit fullscreen mode

The __declspec(dllexport) attribute defined as CALCDLL_API in the code is the key to exporting functions from the DLL, and every function you would like to export from the DLL should be marked with this.

Also notice the “__cdecl” (defined as CALL) before the function name. This declares the calling convention for the function (see the Wikipedia article on x86 calling conventions if you’re not familiar with them).

The default calling convention for C functions in MinGW is cdecl, but it’s a good idea to always explicitly state the calling convention in case some other compiler has a different default. If this happens, your application will likely misbehave or crash as a result of calling one of these functions.

Step 2

We will define our basic functions in calcdll.c

/* calcdll.c

Demonstrates creating a DLL with exported functions
*/

#include "calcdll.h"

int CALL Add(int a, int b) {
  return (a + b);
}

int CALL Subtract(int a, int b) {
  return (a - b);
} 

int CALL Divide(int a, int b) {
  return (a/b);
}

int CALL Multiply(int a, int b) {
  return (a * b);
}
Enter fullscreen mode Exit fullscreen mode

Then, we will compile this DLL. It is necessary to define “CALCDLL_EXPORTS” when compiling the object code, to ensure “CALCDLL_API” is correctly defined in the header. This is done most easily by passing a “-D CALCDLL_EXPORTS” on the command line. We will use a batch file for this: build.bat

/* build.bat

Demonstrates compiling a DLL using a batch file
*/
gcc -c -o calcdll.o calcdll.c -D CALCDLL_EXPORTS
gcc -o calcdll.dll calcdll.o -s -shared -Wl,--subsystem,windows
Enter fullscreen mode Exit fullscreen mode

Run batch file on CMD

C:\Users\sokearth\Documents\CALC>build.bat
Enter fullscreen mode Exit fullscreen mode

Step 3

Let's create our calculator application to utilize our dll

/* calc.c

   Demonstrates using the function imported from the DLL.
*/

#include <stdlib.h>
#include <stdio.h>
#include "calcdll.h"

int main() {
  int a, b, c, d;
  a = Add(10, 5)
  printf("Addition = %d\n", a);

  b = Subtract(10, 5)
  printf("Subtraction = %d\n", b);

  c = Divide(10, 5)
  printf("Division = %d\n", c);

  d = Multiply(10, 5)
  printf("Multiplication = %d\n", d);

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

For the second to last step, we will compile the code to our calculator application into an exe file and run it using another batch file: build_exe.bat

/* build_exe.bat

Demonstrates compiling and running calculator app using a batch file
*/

gcc -c -o calc.o calc.c
gcc -o calc.exe -s calc.o -L. -lcalcdll
calc.exe
Enter fullscreen mode Exit fullscreen mode

Finally, run batch file on CMD

C:\Users\sokearth\Documents\CALC>build_exe.bat
Enter fullscreen mode Exit fullscreen mode

Note

This article demonstrates implicit dynamic linking with GCC. For a guide on how to do explicit dynamic linking, check out the next article on my OpSec series.

Top comments (0)