Skip to content

Commit af14220

Browse files
authored
[linux-port] Support full IID comparison on GCC (#3062)
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.
1 parent 11e04d8 commit af14220

9 files changed

Lines changed: 169 additions & 253 deletions

File tree

include/dxc/Support/WinAdapter.h

Lines changed: 67 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,9 @@
5050
#define _countof(a) (sizeof(a) / sizeof(*(a)))
5151

5252
// If it is GCC, there is no UUID support and we must emulate it.
53-
#ifdef __APPLE__
54-
#define __EMULATE_UUID 1
55-
#else // __APPLE__
56-
#ifdef __GNUC__
5753
#ifndef __clang__
5854
#define __EMULATE_UUID 1
59-
#endif // __GNUC__
6055
#endif // __clang__
61-
#endif // __APPLE__
6256

6357
#ifdef __EMULATE_UUID
6458
#define __declspec(x)
@@ -452,15 +446,14 @@ typedef GUID CLSID;
452446
typedef const GUID &REFGUID;
453447
typedef const GUID &REFCLSID;
454448

455-
#ifdef __EMULATE_UUID
456-
typedef const void *REFIID;
457-
#define IsEqualIID(a, b) a == b
458-
#define IsEqualCLSID(a, b) !memcmp(&a, &b, sizeof(GUID))
459-
#else // __EMULATE_UUID
460449
typedef GUID IID;
461450
typedef IID *LPIID;
462451
typedef const IID &REFIID;
463452
inline bool IsEqualGUID(REFGUID rguid1, REFGUID rguid2) {
453+
// Optimization:
454+
if (&rguid1 == &rguid2)
455+
return true;
456+
464457
return !memcmp(&rguid1, &rguid2, sizeof(GUID));
465458
}
466459

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

484476
//===--------------------- Struct Types -----------------------------------===//
485477

@@ -559,27 +551,63 @@ enum tagSTATFLAG {
559551

560552
#ifdef __EMULATE_UUID
561553

562-
size_t UuidStrHash(const char* k);
563-
564554
// The following macros are defined to facilitate the lack of 'uuid' on Linux.
565-
#define DECLARE_CROSS_PLATFORM_UUIDOF(T) \
566-
public: \
567-
static REFIID uuidof() { return reinterpret_cast<REFIID>(T##_ID); } \
568-
\
569-
private: \
570-
__attribute__((visibility("default"))) static const size_t T##_ID;
571-
572-
#define DEFINE_CROSS_PLATFORM_UUIDOF(T) \
573-
__attribute__((visibility("default"))) const size_t T::T##_ID = \
574-
UuidStrHash(#T);
575-
#define __uuidof(T) T::uuidof()
555+
556+
constexpr uint8_t nybble_from_hex(char c) {
557+
return ((c >= '0' && c <= '9')
558+
? (c - '0')
559+
: ((c >= 'a' && c <= 'f')
560+
? (c - 'a' + 10)
561+
: ((c >= 'A' && c <= 'F') ? (c - 'A' + 10)
562+
: /* Should be an error */ -1)));
563+
}
564+
565+
constexpr uint8_t byte_from_hex(char c1, char c2) {
566+
return nybble_from_hex(c1) << 4 | nybble_from_hex(c2);
567+
}
568+
569+
constexpr uint8_t byte_from_hexstr(const char str[2]) {
570+
return nybble_from_hex(str[0]) << 4 | nybble_from_hex(str[1]);
571+
}
572+
573+
constexpr GUID guid_from_string(const char str[37]) {
574+
return GUID{static_cast<uint32_t>(byte_from_hexstr(str)) << 24 |
575+
static_cast<uint32_t>(byte_from_hexstr(str + 2)) << 16 |
576+
static_cast<uint32_t>(byte_from_hexstr(str + 4)) << 8 |
577+
byte_from_hexstr(str + 6),
578+
static_cast<uint16_t>(
579+
static_cast<uint16_t>(byte_from_hexstr(str + 9)) << 8 |
580+
byte_from_hexstr(str + 11)),
581+
static_cast<uint16_t>(
582+
static_cast<uint16_t>(byte_from_hexstr(str + 14)) << 8 |
583+
byte_from_hexstr(str + 16)),
584+
{byte_from_hexstr(str + 19), byte_from_hexstr(str + 21),
585+
byte_from_hexstr(str + 24), byte_from_hexstr(str + 26),
586+
byte_from_hexstr(str + 28), byte_from_hexstr(str + 30),
587+
byte_from_hexstr(str + 32), byte_from_hexstr(str + 34)}};
588+
}
589+
590+
template <typename interface> inline GUID __emulated_uuidof();
591+
592+
#define CROSS_PLATFORM_UUIDOF(interface, spec) \
593+
struct interface; \
594+
template <> inline GUID __emulated_uuidof<interface>() { \
595+
static const IID _IID = guid_from_string(spec); \
596+
return _IID; \
597+
}
598+
599+
#define __uuidof(T) __emulated_uuidof<typename std::decay<T>::type>()
600+
576601
#define IID_PPV_ARGS(ppType) \
577-
(**(ppType)).uuidof(), reinterpret_cast<void **>(ppType)
602+
__uuidof(decltype(**(ppType))), reinterpret_cast<void **>(ppType)
578603

579604
#else // __EMULATE_UUID
580605

581-
#define DECLARE_CROSS_PLATFORM_UUIDOF(T)
582-
#define DEFINE_CROSS_PLATFORM_UUIDOF(T)
606+
#ifndef CROSS_PLATFORM_UUIDOF
607+
// Warning: This macro exists in dxcapi.h as well
608+
#define CROSS_PLATFORM_UUIDOF(interface, spec) \
609+
struct __declspec(uuid(spec)) interface;
610+
#endif
583611

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

591619
//===--------------------- COM Interfaces ---------------------------------===//
592620

593-
struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
594-
IUnknown() : m_count(0){};
621+
CROSS_PLATFORM_UUIDOF(IUnknown, "00000000-0000-0000-C000-000000000046")
622+
struct IUnknown {
623+
IUnknown() : m_count(0) {};
595624
virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0;
596625
virtual ULONG AddRef();
597626
virtual ULONG Release();
@@ -602,33 +631,27 @@ struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
602631

603632
private:
604633
std::atomic<unsigned long> m_count;
605-
606-
DECLARE_CROSS_PLATFORM_UUIDOF(IUnknown)
607634
};
608635

609-
struct __declspec(uuid("ECC8691B-C1DB-4DC0-855E-65F6C551AF49")) INoMarshal
610-
: public IUnknown {
611-
DECLARE_CROSS_PLATFORM_UUIDOF(INoMarshal)
612-
};
636+
CROSS_PLATFORM_UUIDOF(INoMarshal, "ECC8691B-C1DB-4DC0-855E-65F6C551AF49")
637+
struct INoMarshal : public IUnknown {};
613638

614-
struct __declspec(uuid("00000002-0000-0000-C000-000000000046")) IMalloc
615-
: public IUnknown {
639+
CROSS_PLATFORM_UUIDOF(IMalloc, "00000002-0000-0000-C000-000000000046")
640+
struct IMalloc : public IUnknown {
616641
virtual void *Alloc(size_t size);
617642
virtual void *Realloc(void *ptr, size_t size);
618643
virtual void Free(void *ptr);
619644
virtual HRESULT QueryInterface(REFIID riid, void **ppvObject);
620645
};
621646

622-
struct __declspec(uuid("0C733A30-2A1C-11CE-ADE5-00AA0044773D"))
623-
ISequentialStream : public IUnknown {
647+
CROSS_PLATFORM_UUIDOF(ISequentialStream, "0C733A30-2A1C-11CE-ADE5-00AA0044773D")
648+
struct ISequentialStream : public IUnknown {
624649
virtual HRESULT Read(void *pv, ULONG cb, ULONG *pcbRead) = 0;
625650
virtual HRESULT Write(const void *pv, ULONG cb, ULONG *pcbWritten) = 0;
626-
627-
DECLARE_CROSS_PLATFORM_UUIDOF(ISequentialStream)
628651
};
629652

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

651674
virtual HRESULT Clone(IStream **ppstm) = 0;
652-
653-
DECLARE_CROSS_PLATFORM_UUIDOF(IStream)
654675
};
655676

656677
//===--------------------- COM Pointer Types ------------------------------===//

0 commit comments

Comments
 (0)