Inline assembly: GCC + Watcom.

Апрель 8th, 2009 по SadKo Оставить ответ »

Задумался о кросс-компиляции моего ядрышка GCC (сейчас пока компилируется только Watcom’ом).

Первый большой и краеугольный камень — это, конечно, ассемблерные вставки. Поэтому был придуман механизм, чтобы минимизировать писанину и дублирование ассемблерного кода для обоих компиляторов. С этой целью я сделал некий заголовочный файл, в котором объявил:

#ifdef __WATCOMC__
    // Define Pragmas
    #define inline_func(prag_d, ret_t, body)    ret_t __pragma(#prag_d) body;
    #define inline_proc(prag_d, body)           void  __pragma(#prag_d) body;
#endif /* __WATCOMC__ */

#ifdef __GNUC__
    // Define Pragmas
    #define inline_func(prag_d, ret_t, body)        \
        static __inline ret_t body                  \
        {                                           \
            ret_t __result;                         \
            __asm__ __volatile__ (                  \
                    ".intel_syntax noprefix"        \
                    prag_d                          \
            );                                      \
            return __result;                        \
        }

    #define inline_proc(prag_d, body)               \
        static __inline void body                   \
        {                                           \
            __asm__ __volatile__ (                  \
                    ".intel_syntax noprefix"        \
                    prag_d                          \
            );                                      \
        }
#endif /* __GNUC__ */

Заметим, что для GNU GCC я заведомо врубил синтаксис интела (ну не люблю я синтаксис AT&T, да и нафиг он не нужен на i386, на мой взгляд).

Теперь, допустим, захотел я сделать функцию __strlen на ассемблере. Для этого я ворочу соответствующие макросы:


#define __I386_STREND_IMPL          \
        "mov    ecx, -1"            \
        "xor    al, al"             \
        "repne  scasb"

// macro for strlen() function
#define __I386_STRLEN               \
        __I386_STREND_IMPL          \
        "mov    eax, -2"            \
        "sub    eax, ecx"

И связываю эти макросы с параметрами для каждого компилятора по-своему:

#if defined(__WATCOMC__)
    // strlen function bindings for Watcom
    #pragma aux I386_STRLEN     =       \
            __I386_STRLEN               \
            parm caller [edi]           \
            value [eax]                 \
            modify [edi ecx]
#elif defined(__GNUC__)
    // strlen function bindings for GCC
    #define I386_STRLEN                 \
            __I386_STRLEN               \
            : "=a"(__result)            \
            : "D"(str)
#endif /* compiler detection */

После чего осталось объявить прототип функции:

inline_func(I386_STRLEN,    size_t,     __strlen(const char *str)                       )

Всё, теперь я могу использовать функцию __strlen, и она будет инлайниться во всех участках кода как для GCC, так и для Watcom. Замечательно, не правда ли?

Реклама

5 комментариев

  1. Давно пора :) Молодец!

  2. Вот :) мне бы твои заботы :)

  3. В смысле?

  4. А мне кажется интеловский синтаксис — убог.
    Я сколько пытался себя заставить на нём писать — так и не смог.
    Порядок операндов добивает. *_*

  5. На вкус и цвет :)

Добавить комментарий

Blue Captcha Image
Refresh

*