GetModuleHandle(NULL) on Linux
The documentation for dlopen
(3) states:
The function
dlopen()
loads the dynamic library file named by the
null-terminated stringfilename
and returns an opaque "handle" for the
dynamic library. Iffilename
isNULL
, then the returned handle is for
the main program.
Therefore, you can use the value returned by dlopen(NULL)
as the handle
argument to dlsym()
.
GetModuleHandle(NULL) vs hInstance
In an EXE, it does not make any difference. hInstance
from WinMain()
and GetModuleHandle(NULL)
both refer to the same HINSTANCE
(the module of the .exe file). But it does make a difference if you are creating windows inside of a DLL instead, since you have to use the DLL's hInstance
but GetModuleHandle(NULL)
will still return the HINSTANCE
of the EXE that loaded the DLL.
Why doesn't this code work (Please See Details)?
The code fails because GetProcAddress
requires the supplied symbol to have been exported from the module in question. That is, the symbol must have been listed in the PE module's export table. You do not export the symbol, and so GetProcAddress
cannot find it. Hence GetProcAddress
returns NULL
. If you wish to use GetProcAddress
then you must export the symbol. Either by naming it in a .def file, or by using __declspec(dllexport)
.
Some other comments:
- You appear to have a mismatch of calling conventions,
stdcall
andcdecl
. - You don't perform any error checking. For these particular function you need to check the return value. If that indicates that the function has failed, then call
GetLastError
for extended error information.
How does GetModuleHandle work in Visual c++
You can only call GetModuleHandle(L"C:\\Users\\Steve\\Desktop\\stub.exe");
when you're running C:\Users\Steve\Desktop\stub.exe
.
But in general, you don't call GetModuleHandle
for your EXE name. Since there's only one EXE per process, you just call GetModuleHandle(0)
.
How to determine if a so file has been loaded or not?
You can actually use dlopen
to check this, with the RTLD_NOLOAD
flag:
Don't load the library. This can be used to test if the library is already resident (
dlopen()
returnsNULL
if it is not, or the library's handle if it is resident).
Get loaded address of a ELF binary, dlopen is not working as expected
On Linux, dlopen
doesn't return the address where the ELF binary was loaded. It returns struct link_map
instead, which has .l_addr
member. So you'll want something like:
struct link_map *lm = (struct link_map*) dlopen(0, RTLD_NOW);
printf("%p\n", lm->l_addr);
However, despite what comment in /usr/include/link.h
says, .l_addr
is actually not a load address either. Instead, it's the difference between where ELF image was linked to load, and where it was actually loaded.
For non-PIE main executable, that difference is always 0. For non-prelinked shared library, that difference is always the load address (because non-prelinked ELF shared libraries are linked to load at address 0).
So how do you find the base address of the main executable? The easiest method is to use this code (linked into main executable):
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
static int
callback(struct dl_phdr_info *info, size_t size, void *data)
{
int j;
const char *cb = (const char *)&callback;
const char *base = (const char *)info->dlpi_addr;
const ElfW(Phdr) *first_load = NULL;
for (j = 0; j < info->dlpi_phnum; j++) {
const ElfW(Phdr) *phdr = &info->dlpi_phdr[j];
if (phdr->p_type == PT_LOAD) {
const char *beg = base + phdr->p_vaddr;
const char *end = beg + phdr->p_memsz;
if (first_load == NULL) first_load = phdr;
if (beg <= cb && cb < end) {
// Found PT_LOAD that "covers" callback().
printf("ELF header is at %p, image linked at 0x%zx, relocation: 0x%zx\n",
base + first_load->p_vaddr, first_load->p_vaddr, info->dlpi_addr);
return 1;
}
}
}
return 0;
}
int
main(int argc, char *argv[])
{
dl_iterate_phdr(callback, NULL);
exit(EXIT_SUCCESS);
}
Here is what you should see on 32-bit system:
$ gcc -g t.c -ldl -m32 && ./a.out
ELF header is at 0x8048000, image linked at 0x8048000, relocation: 0x0
$ gcc -g t.c -ldl -m32 -pie -fPIE && ./a.out
ELF header is at 0xf779a000, image linked at 0x0, relocation: 0xf779a000
(The last address: 0xf779a000
will vary from run to run if you have address randomization enabled (as you should)).
How to check if stdout has been redirected to NUL on Windows (a.k.a. /dev/null on Linux)?
I figured it out myself. It's annoying.
#include <Windows.h>
#include <io.h>
#pragma comment(lib, "ntdll.lib") // can instead use GetProcAddress (below)
extern "C" NTSTATUS __stdcall NtQueryVolumeInformationFile(
HANDLE FileHandle, struct _IO_STATUS_BLOCK *IoStatusBlock,
void *FsInformation, unsigned long Length,
enum _FSINFOCLASS FsInformationClass);
bool isdevnull(FILE *file)
{
struct FILE_FS_DEVICE_INFORMATION
{ unsigned long DeviceType, Characteristics; } fsinfo;
struct { void *info, *status; } iosb;
typedef NTSTATUS (__stdcall *PNTQIF)(
HANDLE FileHandle, struct _IO_STATUS_BLOCK *IoStatusBlock,
void *FsInformation, unsigned long Length,
enum _FSINFOCLASS FsInformationClass);
PNTQIF const ntqif =
true // True if you have ntdll.lib, false otherwise
? NtQueryVolumeInformationFile
: (PNTQIF) GetProcAddress(
GetModuleHandle(TEXT("ntdll.dll")),
"NtQueryVolumeInformationFile");
return ntqif(
(HANDLE) _get_osfhandle(_fileno(stdout)),
(struct _IO_STATUS_BLOCK *)&iosb,
&fsinfo, sizeof(fsinfo),
(enum _FSINFOCLASS)4
) == 0 && fsinfo.DeviceType == 0x00000015 /*FILE_DEVICE_NULL*/;
}
int main()
{
bool b = isdevnull(stdout);
}
Related Topics
Set Environment Variables for Non-Interactive Shell
What's the Max File Mapping Size in 64Bits MAChine
Ignoring Comma in Field of CSV File with Awk
Difference Between Kernel, Kernel-Thread and User-Thread
Best Way to Make Linux Web Services
Objdump and Resolving Linkage of Local Function Calls
Jenkins to Run Maven Build on Linux or Windows
Does Not Work to Execute Command in Double Brackets in Bash
I.Mx35 Suspend CPU and Ddr2 from Iram
Synchronizing Four Shell Scripts to Run One After Another in Unix
Shell Script for Process Monitoring
Jna Link Issue While Starting Cassandra Rhel 6.5
Qt Version Is Not Properly Installed, Please Run Make Install
How to Join a Thread in Linux Kernel
"Cannot Write to Log File Pg_Upgrade_Internal.Log" When Upgrading from Postgresql 9.1 to 9.3