Choosing which function to call based on the architecture

120 Views Asked by At

I'm working primarily in NASM, however I'm also making a C/C++ header file that uses externs to import functions from NASM to the project. I'm worried about someone using the x64 NASM in a x86 environment. I know this isn't possible(to run x64 in x86) because of the invalid operand sizing errors I'm getting when I compile. I'm planning on re-making the project, but in x86, so it can work in either x86 or x64.

My trouble begins when declaring the extern "C" functions.

I want to keep a single function name(openfile, for example), but have the definition be based off of the x64 variant or the x86 variant, depending on whether the macro arch_x64 or arch_x86 is defined.

I can use preprocess for this, like the example below:

#ifdef arch_x64
    int value = 1;
#elif arch_x86
    int value = 0;
#endif

and if I declare arch_x64 in my source project, value is 1.

I want to use this same method for the function openfile. Based on the architecture, the function definition should be either the x64 or x86.

I could do

#ifdef arch_x64
    extern "C" void openfile64();
#elif arch_x86
    extern "C" void openfile32();
#endif

void openfile()
{
    #ifdef arch_x64
        openfile64(); // 64-bit version
    #elif arch_x86
        openfile32(); // 32-bit version
    #endif
};

and that'd work, but then the openfile64 function is accessible, which could be confusing.

Is there a way to assign openfile's definition to either the x64(openfile64) or x86(openfile32) version?

EDIT

I just now realized that Jan Schultke meant using a .cpp file or similar to hide openfile64. This could work, but I can't detect a #define across .cpp files. I'd need to send something down to the .cpp file that tells it what functions to set it as(or I'm thinking too much and there's a simpler way). That "something"(again, unles I'm thinking too hard) would also be exposed in the header file. I don't want to expose anything new besides the function openfile.

2

There are 2 best solutions below

1
A. K. On

What you are looking for is called ifunc (indirect function). It is a feature of the GNU/GCC toolchain that allows a developer to create multiple implementations of a given function and to select one of them at runtime using a resolver function. A function attribute is added to specify the resolver function. This is how correct implementation of glibc functions like memcpy/memmove is called for a particular microarchitecture. This is also supported by llvm toolchain.

References:

0
Jarod42 On

Using your toolchain might be an alternative:

code_x86.cpp

#ifdef arch_x64
# error "wrong arch"
#endif

void openfile() // openfile32 implementation
{
    /*..*/ // 32-bit version
}

code_x64.cpp

#ifdef arch_x86
# error "wrong arch"
#endif

void openfile() // openfile64 implementation 
{
    /*..*/ // 64-bit version
}

and then include only files matching your architecture.