loadlibrary icon indicating copy to clipboard operation
loadlibrary copied to clipboard

Got "attempted to call an unknown symbol" for an hello world example

Open dov opened this issue 6 years ago • 1 comments

In order to learn how to use the loadlbrary library with the goal of accessing a commercial win32 library from linux, I started off with a simple hello world example.

Here are my files:

  • say-hello.h
#ifndef SAY_HELLO_H
#define SAY_HELLO_H
void say_hello();
#endif /* SAY-HELLO */

  • say-hello.c
#include <stdio.h>

void say_hello()
{
  printf("Say Hello!\n");
}
  • hello-main.c - For testing the dll with wine
#include "say-hello.h"

int main(int argc, char*argv[])
{
  say_hello();
}
  • The build command of the dll:
i686-w64-mingw32-gcc -o hello-main.obj -c -O2 -mms-bitfields hello-main.c
i686-w64-mingw32-gcc -o say-hello.obj -c -fPIC -O2 -mms-bitfields say-hello.c
i686-w64-mingw32-gcc -o say-hello.dll -shared say-hello.obj
i686-w64-mingw32-gcc -o hello-main.exe hello-main.obj say-hello.dll
  • Testing the dll works:
wine hello-main.exe
000b:fixme:winediag:start_process Wine Staging 4.0-rc2 is a testing version containing experimental patches.
000b:fixme:winediag:start_process Please mention your exact version when filing bug reports on winehq.org.
Say Hello!

Now I wanted to load this dll into load library and I started at mpclient.c sources and removed as much as I could and then tried to call my say_hello() function. This is what I got:

#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>

#include "winnt_types.h"
#include "pe_linker.h"
#include "ntoskernel.h"

int main(int argc, char **argv, char **envp)
{
    PIMAGE_DOS_HEADER DosHeader;
    PIMAGE_NT_HEADERS PeHeader;
    struct pe_image image = {
        .entry  = NULL,
        .name   = "say-hello.dll",
    };

    // Load the mpengine module.
    if (pe_load_library(image.name, &image.image, &image.size) == false) {
        printf("You must add the dll and vdm files to the engine directory");
        return 1;
    }

    // Handle relocations, imports, etc.
    link_pe_images(&image, 1);

    // Fetch the headers to get base offsets.
    DosHeader   = (PIMAGE_DOS_HEADER) image.image;
    PeHeader    = (PIMAGE_NT_HEADERS)(image.image + DosHeader->e_lfanew);

    // Try calling into the library.
    void (*SayHelloPtr)();
    if (get_export("say_hello", &SayHelloPtr) != -1) {
        (*SayHelloPtr)();
    }
    else
        printf("Failed getting pointer to say_hello()!\n");
    
    return 0;
}

It coompiles, the dll loads, the say_hello symbol is found, but it then crashes at (*SayHelloPtr)(). What did I miss?

Thanks!

dov avatar Dec 29 '18 19:12 dov

After I wrote the above, I realized that perhaps the "attempt to call an unknown symbol" error is the call to printf(). I then added a new function to my dll:

int32_t add_hello(int32_t a, int32_t b);

and called it as follows:

    // Try calling into the library.
    int32_t (*AddHelloPtr)(int32_t a, int32_t b);
    if (get_export("add_hello", &AddHelloPtr) != -1) {
        int a=10,b=32;
        printf("%d+%d=%d\n", a,b,AddHelloPtr(a,b));
    }
    else
        printf("Failed getting pointer to say_hello()!\n");

and this worked!

But I still wonder how would I load the windows CRT library so that I can call printf (and other io functions)? Or is there a way to redirect the DLL printf() call to the gcc libc printf() .

dov avatar Dec 29 '18 21:12 dov