Skip to content

Commit

Permalink
[linux-port] Support full IID comparison on GCC (#3062)
Browse files Browse the repository at this point in the history
The fallback layer for GCC currently uses pointer comparison to match
IIDs as uuid tagging for types is not supported.
Thus, when an external program dlopens libdxcompiler and calls
with a proper REFIID these will not match internal pointers and result
in E_NOINTERFACE.

Note that the reverted patches before this commit alleviated the
situation somewhat by replacing the pointer with a hash of the interface
name. While this again grants a stable value to be used when called from
external binaries these (usually FFI wrappers) now need to understand
whether the library has been compiled with full IID support (as a binary
compiled with Clang has no such limitations), and then pass the hash
anywhere they'd otherwise pass an IID.

WIP: Not all IIDs are added yet, which requires the extra "empty-GUID"
check in IsEqualIID.
  • Loading branch information
MarijnS95 authored Nov 20, 2020
1 parent 11e04d8 commit af14220
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 253 deletions.
113 changes: 67 additions & 46 deletions include/dxc/Support/WinAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,9 @@
#define _countof(a) (sizeof(a) / sizeof(*(a)))

// If it is GCC, there is no UUID support and we must emulate it.
#ifdef __APPLE__
#define __EMULATE_UUID 1
#else // __APPLE__
#ifdef __GNUC__
#ifndef __clang__
#define __EMULATE_UUID 1
#endif // __GNUC__
#endif // __clang__
#endif // __APPLE__

#ifdef __EMULATE_UUID
#define __declspec(x)
Expand Down Expand Up @@ -452,15 +446,14 @@ typedef GUID CLSID;
typedef const GUID &REFGUID;
typedef const GUID &REFCLSID;

#ifdef __EMULATE_UUID
typedef const void *REFIID;
#define IsEqualIID(a, b) a == b
#define IsEqualCLSID(a, b) !memcmp(&a, &b, sizeof(GUID))
#else // __EMULATE_UUID
typedef GUID IID;
typedef IID *LPIID;
typedef const IID &REFIID;
inline bool IsEqualGUID(REFGUID rguid1, REFGUID rguid2) {
// Optimization:
if (&rguid1 == &rguid2)
return true;

return !memcmp(&rguid1, &rguid2, sizeof(GUID));
}

Expand All @@ -479,7 +472,6 @@ inline bool IsEqualIID(REFIID riid1, REFIID riid2) {
inline bool IsEqualCLSID(REFCLSID rclsid1, REFCLSID rclsid2) {
return IsEqualGUID(rclsid1, rclsid2);
}
#endif // __EMULATE_UUID

//===--------------------- Struct Types -----------------------------------===//

Expand Down Expand Up @@ -559,27 +551,63 @@ enum tagSTATFLAG {

#ifdef __EMULATE_UUID

size_t UuidStrHash(const char* k);

// The following macros are defined to facilitate the lack of 'uuid' on Linux.
#define DECLARE_CROSS_PLATFORM_UUIDOF(T) \
public: \
static REFIID uuidof() { return reinterpret_cast<REFIID>(T##_ID); } \
\
private: \
__attribute__((visibility("default"))) static const size_t T##_ID;

#define DEFINE_CROSS_PLATFORM_UUIDOF(T) \
__attribute__((visibility("default"))) const size_t T::T##_ID = \
UuidStrHash(#T);
#define __uuidof(T) T::uuidof()

constexpr uint8_t nybble_from_hex(char c) {
return ((c >= '0' && c <= '9')
? (c - '0')
: ((c >= 'a' && c <= 'f')
? (c - 'a' + 10)
: ((c >= 'A' && c <= 'F') ? (c - 'A' + 10)
: /* Should be an error */ -1)));
}

constexpr uint8_t byte_from_hex(char c1, char c2) {
return nybble_from_hex(c1) << 4 | nybble_from_hex(c2);
}

constexpr uint8_t byte_from_hexstr(const char str[2]) {
return nybble_from_hex(str[0]) << 4 | nybble_from_hex(str[1]);
}

constexpr GUID guid_from_string(const char str[37]) {
return GUID{static_cast<uint32_t>(byte_from_hexstr(str)) << 24 |
static_cast<uint32_t>(byte_from_hexstr(str + 2)) << 16 |
static_cast<uint32_t>(byte_from_hexstr(str + 4)) << 8 |
byte_from_hexstr(str + 6),
static_cast<uint16_t>(
static_cast<uint16_t>(byte_from_hexstr(str + 9)) << 8 |
byte_from_hexstr(str + 11)),
static_cast<uint16_t>(
static_cast<uint16_t>(byte_from_hexstr(str + 14)) << 8 |
byte_from_hexstr(str + 16)),
{byte_from_hexstr(str + 19), byte_from_hexstr(str + 21),
byte_from_hexstr(str + 24), byte_from_hexstr(str + 26),
byte_from_hexstr(str + 28), byte_from_hexstr(str + 30),
byte_from_hexstr(str + 32), byte_from_hexstr(str + 34)}};
}

template <typename interface> inline GUID __emulated_uuidof();

#define CROSS_PLATFORM_UUIDOF(interface, spec) \
struct interface; \
template <> inline GUID __emulated_uuidof<interface>() { \
static const IID _IID = guid_from_string(spec); \
return _IID; \
}

#define __uuidof(T) __emulated_uuidof<typename std::decay<T>::type>()

#define IID_PPV_ARGS(ppType) \
(**(ppType)).uuidof(), reinterpret_cast<void **>(ppType)
__uuidof(decltype(**(ppType))), reinterpret_cast<void **>(ppType)

#else // __EMULATE_UUID

#define DECLARE_CROSS_PLATFORM_UUIDOF(T)
#define DEFINE_CROSS_PLATFORM_UUIDOF(T)
#ifndef CROSS_PLATFORM_UUIDOF
// Warning: This macro exists in dxcapi.h as well
#define CROSS_PLATFORM_UUIDOF(interface, spec) \
struct __declspec(uuid(spec)) interface;
#endif

template <typename T> inline void **IID_PPV_ARGS_Helper(T **pp) {
return reinterpret_cast<void **>(pp);
Expand All @@ -590,8 +618,9 @@ template <typename T> inline void **IID_PPV_ARGS_Helper(T **pp) {

//===--------------------- COM Interfaces ---------------------------------===//

struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
IUnknown() : m_count(0){};
CROSS_PLATFORM_UUIDOF(IUnknown, "00000000-0000-0000-C000-000000000046")
struct IUnknown {
IUnknown() : m_count(0) {};
virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0;
virtual ULONG AddRef();
virtual ULONG Release();
Expand All @@ -602,33 +631,27 @@ struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {

private:
std::atomic<unsigned long> m_count;

DECLARE_CROSS_PLATFORM_UUIDOF(IUnknown)
};

struct __declspec(uuid("ECC8691B-C1DB-4DC0-855E-65F6C551AF49")) INoMarshal
: public IUnknown {
DECLARE_CROSS_PLATFORM_UUIDOF(INoMarshal)
};
CROSS_PLATFORM_UUIDOF(INoMarshal, "ECC8691B-C1DB-4DC0-855E-65F6C551AF49")
struct INoMarshal : public IUnknown {};

struct __declspec(uuid("00000002-0000-0000-C000-000000000046")) IMalloc
: public IUnknown {
CROSS_PLATFORM_UUIDOF(IMalloc, "00000002-0000-0000-C000-000000000046")
struct IMalloc : public IUnknown {
virtual void *Alloc(size_t size);
virtual void *Realloc(void *ptr, size_t size);
virtual void Free(void *ptr);
virtual HRESULT QueryInterface(REFIID riid, void **ppvObject);
};

struct __declspec(uuid("0C733A30-2A1C-11CE-ADE5-00AA0044773D"))
ISequentialStream : public IUnknown {
CROSS_PLATFORM_UUIDOF(ISequentialStream, "0C733A30-2A1C-11CE-ADE5-00AA0044773D")
struct ISequentialStream : public IUnknown {
virtual HRESULT Read(void *pv, ULONG cb, ULONG *pcbRead) = 0;
virtual HRESULT Write(const void *pv, ULONG cb, ULONG *pcbWritten) = 0;

DECLARE_CROSS_PLATFORM_UUIDOF(ISequentialStream)
};

struct __declspec(uuid("0000000c-0000-0000-C000-000000000046")) IStream
: public ISequentialStream {
CROSS_PLATFORM_UUIDOF(IStream, "0000000c-0000-0000-C000-000000000046")
struct IStream : public ISequentialStream {
virtual HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition) = 0;
virtual HRESULT SetSize(ULARGE_INTEGER libNewSize) = 0;
Expand All @@ -649,8 +672,6 @@ struct __declspec(uuid("0000000c-0000-0000-C000-000000000046")) IStream
virtual HRESULT Stat(STATSTG *pstatstg, DWORD grfStatFlag) = 0;

virtual HRESULT Clone(IStream **ppstm) = 0;

DECLARE_CROSS_PLATFORM_UUIDOF(IStream)
};

//===--------------------- COM Pointer Types ------------------------------===//
Expand Down
Loading

0 comments on commit af14220

Please sign in to comment.