Что может привести к тому, что аргументы P /Invoke будут не в порядке при передаче?

Эта проблема возникает именно в ARM, а не в x86 или x64. Я сообщил об этой проблеме пользователю и смог воспроизвести ее с помощью UWP на Raspberry Pi 2 через Windows IoT. Я уже сталкивался с подобными проблемами с несоответствующими соглашениями о вызовах, но я указываю Cdecl в объявлении P /Invoke и пытался явно добавить __cdecl на нативной стороне с теми же результатами. Вот некоторая информация:

Объявление P /Invoke ( ссылка ):

[DllImport(Constants.DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern FLSliceResult FLEncoder_Finish(FLEncoder* encoder, FLError* outError);

C # структурирует ( как непрозрачный указатель . При вызове метода выше на x86 и x64 все работает гладко, но на ARM я наблюдаю следующее. Адрес первого аргумента является адресом второго аргумента, а второй аргумент является нулевым (например, когда я регистрирую адреса на стороне C #, я получаю, например, 0x054f59b8 и 0x0583f3bc, но затем на собственной стороне аргументы 0x0583f3bc и 0x00000000). Что может вызвать проблемы такого рода? У кого-нибудь есть идеи, потому что я в тупике ...

Вот код, который я запускаю для воспроизведения:

internal unsafe partial struct FLSliceResult
{
    public void* buf;
    private UIntPtr _size;

    public ulong size
    {
        get {
            return _size.ToUInt64();
        }
        set {
            _size = (UIntPtr)value;
        }
    }
}

internal enum FLError
{
    NoError = 0,
    MemoryError,
    OutOfRange,
    InvalidData,
    EncodeError,
    JSONError,
    UnknownValue,
    InternalError,
    NotFound,
    SharedKeysStateError,
}

internal unsafe struct FLEncoder
{
}

Запуск приложения на C ++ со следующими параметрами работает нормально:

FLSliceResult FLEncoder_Finish(FLEncoder, FLError*);

Эта логика может вызвать сбой с помощью самого последнего разработчика. build но, к сожалению, я еще не выяснил, как надежно предоставить нативные символы отладки через Nuget, чтобы его можно было проходить (кажется, только сборка всего из исходного кода) ... так что отладка немного неловко, потому что нужно создавать как собственные, так и управляемые компоненты. Я открыт для предложений о том, как сделать это проще, хотя, если кто-то хочет попробовать. Но если кто-то сталкивался с этим раньше или имеет какие-либо идеи о том, почему это происходит, добавьте ответ, спасибо! Конечно, если кто-то захочет воспроизвести случай (либо простой для создания, не предусматривающий переход с исходного кода, либо сложный для создания, который это делает), тогда оставьте комментарий, но я не хочу проходить процесс его создания. если никто не собирается его использовать (я не уверен, насколько популярно использование Windows на реальном ARM)

РЕДАКТИРОВАТЬ Интересное обновление: если я "подделаю" подпись в C # и удаляю 2-й параметр, то первый из них проходит через ОК.

РЕДАКТИРОВАТЬ 2 Второе интересное обновление: если я изменю определение размера C # FLSliceResult с unsafe { var enc = Native.FLEncoder_New(); Native.FLEncoder_BeginDict(enc, 1); Native.FLEncoder_WriteKey(enc, "answer"); Native.FLEncoder_WriteInt(enc, 42); Native.FLEncoder_EndDict(enc); FLError err; NativeRaw.FLEncoder_Finish(enc, &err); Native.FLEncoder_Free(enc); } на ---- +: = 6 =: + ---- тогда аргументы вводятся правильно ... что не имеет смысла, так как auto enc = FLEncoder_New(); FLEncoder_BeginDict(enc, 1); FLEncoder_WriteKey(enc, FLSTR("answer")); FLEncoder_WriteInt(enc, 42); FLEncoder_EndDict(enc); FLError err; auto result = FLEncoder_Finish(enc, &err); FLEncoder_Free(enc); в ARM должен быть без знака int.

РЕДАКТИРОВАТЬ 3 Добавление UIntPtr к определению в C # также делает эту работу, но ПОЧЕМУ? sizeof (FLSliceResult) в C /C ++ для этой архитектуры возвращает 8, как и должно быть. Установка того же размера в C # вызывает сбой, но установка его в 12 заставляет его работать.

РЕДАКТИРОВАТЬ 4 Я минимизировал контрольный пример, чтобы можно было также написать контрольный пример C ++. В C # UWP это не удается, но в C ++ UWP это успешно.

РЕДАКТИРОВАТЬ 5 Здесь приведены разборные инструкции для C ++ и C # для сравнения (хотя C # я не уверен, сколько взять, поэтому я допустил ошибку, приняв слишком много)

РЕДАКТИРОВАТЬ 6 Дальнейший анализ показывает, что во время «хорошего» прогона, когда я вру и говорю, что структура на C # составляет 12 байтов, возвращаемое значение передается в регистр r0 с двумя другими аргументами входя через r1, r2. Тем не менее, при неудачном запуске это сдвигается так, что два аргумента поступают через r0, r1, а возвращаемое значение находится где-то еще (указатель стека?)

РЕДАКТИРОВАТЬ 7 Я проконсультировался с Стандарт вызова процедур для архитектуры ARM . Я нашел эту цитату: «Составной тип больше 4 байтов или размер которого не может быть определен статически ни вызывающим, ни вызываемый, хранится в памяти по адресу, переданному в качестве дополнительного аргумента при вызове функции (§5.5, правило А.4). Память, которая будет использоваться для результата, может быть изменена в любой точке во время вызова функции. "Это означает, что переход в r0 является правильным поведением, так как дополнительный аргумент подразумевает первый (так как в соглашении о вызовах C нет способа указать число аргументов). Интересно, не перепутает ли CLR это правило с фундаментальным 64-битными типами данных: «Фундаментальный тип данных размером в два слова (например, long long, double и 64»). контейнерные векторы) вернулся в r0 и r1. "

РЕДАКТИРОВАТЬ 8 Хорошо, есть много свидетельств, указывающих на то, что CLR делает неправильные вещи, поэтому я подал отчет об ошибках . Я надеюсь, что кто-то заметит это между всеми автоматическими ботами, публикующими сообщения об этом репо: -S.

79 голосов | спросил borrrden 20 J0000006Europe/Moscow 2017, 01:59:56

1 ответ


0

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

ответил borrrden 14 Jam1000000amSun, 14 Jan 2018 04:02:44 +030018 2018, 04:02:44

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132