Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Вопросы по реализации - vtable и target #2

Closed
bapho-bush opened this issue Aug 14, 2023 · 8 comments
Closed

Вопросы по реализации - vtable и target #2

bapho-bush opened this issue Aug 14, 2023 · 8 comments
Labels
documentation Improvements or additions to documentation question Further information is requested

Comments

@bapho-bush
Copy link

Хочу задать пару вопросов так как сам когда-то хотел реализовать подобный шаблон:

  1. Как реализовали уход от MSVC? Мне казалось, что для этого нужно соблюдение MSVC ABI. Но Rust основан на clang, а значит там llvm ABI. Я знаю, что компилятор Rust умеет собирать под MSVC ABI, но я не вижу в Cargo.toml или readme информации о таргетах;
  2. На каких операционных системах пробовал собрать? И какие контексты – клиентский или серверный?
  3. Поскольку API у 1С реализовано через наследование с virtual’ами, мне казалось, что нужно самому писать vtable’ы, чтоб платформа конкретно вызовы обрабатывала. Но в то же время, для винды мне казалось, что сборка выглядит как просто вызов функций из стандартной DLL’ки. Можешь помочь разобраться в vtable’ах? Я посмотрел сорцы и увидел код с memorymanagervtable. И хотел бы уточнить:
    a. Почему target_family = unix?
    b. Структура vtable’ов – implementation defined для компиляторов C++. Почему именно такая структура?
@bapho-bush
Copy link
Author

Из переписки:

image

@Sebekerga
Copy link
Owner

Sebekerga commented Aug 15, 2023

Вот оригинальный репозиторий, там автор тоже приводит пояснения: https://github.com/medigor/example-native-api-rs
Также оттуда пример с VTable в различных компиляторах: https://godbolt.org/z/KM3jaWMWs

Хорошим примером будет реализация MemoryManagerVTable - относительно маленькой структуры. В C++ выглядит так:

class IMemoryManager
{
public:
    virtual ~IMemoryManager() {}
    virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
    virtual void ADDIN_API FreeMemory (void** pMemory) = 0;
};

Получить представление VTable удобно на godbolt (https://godbolt.org/z/WGWa5E49M):

  • Для clang
    VTable indices for 'IMemoryManager' (4 entries).
      0 | IMemoryManager::~IMemoryManager() [complete]
      1 | IMemoryManager::~IMemoryManager() [deleting]
      2 | void IMemoryManager::AllocMemory()
      3 | void IMemoryManager::FreeMemory()
    
  • Для msvc
    Test::$vftable@:
    	| &Test_meta
    	|  0
     0	| &Test::{dtor} 
     1	| &IMemoryManager::AllocMemory 
     2	| &IMemoryManager::FreeMemory 
    

В rust переносим, вынеся все внутря в MemoryManagerVTable, т.к. :

|  +--- (base class IMemoryManager)
|  | {vfptr}
|  +---
#[repr(C)]
struct MemoryManagerVTable {
    dtor: usize,
    #[cfg(target_family = "unix")] 
    dtor2: usize,  // второй поинтер нужен только для имитации таблиц clang, а это случается только когда компилируем под unix
    alloc_memory: unsafe extern "system" fn(&MemoryManager, *mut *mut c_void, c_ulong) -> bool,
    free_memory: unsafe extern "system" fn(&MemoryManager, *mut *mut c_void),
}

#[repr(C)]
pub struct MemoryManager {
    vptr: &'static MemoryManagerVTable,
}

Я не могу найти, где прям четко написано это, но мое понимание такое, что 1С под виндой ждет скомпилированное только MSVC, а под linux соответственно clang или gcc ("In general, Clang is highly compatible with the GCC inline assembly extensions, allowing the same set of constraints, modifiers and operands as GCC inline assembly.")

@Sebekerga Sebekerga added documentation Improvements or additions to documentation question Further information is requested labels Aug 15, 2023
@bapho-bush
Copy link
Author

Я не могу найти, где прям четко написано это, но мое понимание такое, что 1С под виндой ждет скомпилированное только MSVC, а под linux соответственно clang или gcc

На сколько я помню, это в каком-то докладе говорилось техническом. По-моему в том, где рассказывали как потребление памяти анализируют. Там говорили, что они завязались на MSVC на винде и на gcс на лине. И ещё свой аллоктор используют, а не системный.

@bapho-bush
Copy link
Author

https://docs.rs/vtable/latest/vtable/

Мне кажется для vtable'ов нужно посмотреть в сторону этого крейта. Уж очень мне не нравится формирование vtable'ов по дизасму с годболта.

И ещё смущает, что для сборки не используется msvc-target. Как бы не было UB.

@Sebekerga
Copy link
Owner

Sebekerga commented Aug 17, 2023

A #[vtable] macro to annotate a VTable struct to generate the traits and structure to safely work with it.

Этот крейт не даст возможности строить VTable'ы, их всё так же придется переность "руками". Я попробовал, крейт так же не умеет работать с #[cfg(target_family = "unix")] префиксами, т.е. здесь даже не получится особо упроситить вид кода, т.к. придется иметь две разные структуры для разных ОС.

И ещё смущает, что для сборки не используется msvc-target

Не совсем понимаю проблему. Если вы собираете компоненту для работы под Windows, вам придется ее собрать, указав через --target целевую платформу. Это может быть x86_64-pc-windows-gnu, x86_64-pc-windows-msvc, i686-pc-windows-gnu или i686-pc-windows-msvc, неважно, т.к. VTable'ы в нашем случае строго прописаны и будут соответствовать таблицам msvc.

Edit

Я в общем-то не против использования удобных макросов, просто самому пока что не охота заниматься этой частью. Но если будут пулл реквесты, я конечно же их приму

@bapho-bush
Copy link
Author

Не совсем понимаю проблему.
Я опасаюсь, что это разные ABI. Что вопрос не только в vtable'ах в GNU и MSVC ABI.

Этот крейт не даст возможности строить VTable'ы, их всё так же придется переность "руками". Я попробовал, крейт так же не умеет работать с #[cfg(target_family = "unix")] префиксами, т.е. здесь даже не получится особо упроситить вид кода, т.к. придется иметь две разные структуры для разных ОС.

Про переносить "руками" - да, понимаю. Предложил ради остальных описанных трансформаций. Предполагал, что будут ещё полезности. Если нет - окей.

https://docs.rs/vtable/latest/vtable/attr.vtable.html

image

@Sebekerga
Copy link
Owner

Еще одна проблема с этим крейтом в том, что он использует extern "C", но такое не подойдет, т.к. нам нужен extern "system" для Windows:

// из библиотеки 1С, types.h
#ifdef _WINDOWS
#define ADDIN_API __stdcall
#else
#define ADDIN_API
#endif //_WINDOWS
// из библиотеки 1С, IMemoryManager.h
class IMemoryManager
{
public:
    virtual ~IMemoryManager() {}
    virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0;
    virtual void ADDIN_API FreeMemory (void** pMemory) = 0;
};

для референса: https://doc.rust-lang.org/reference/items/external-blocks.html

@bapho-bush
Copy link
Author

bapho-bush commented Aug 17, 2023

т.к. нам нужен extern "system" для Windows:

Да, тогда и правда не подойдёт

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants