ассемблер в СИ

Тема в разделе "WASM.BEGINNERS", создана пользователем Alisia, 31 окт 2009.

  1. Alisia

    Alisia New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2009
    Сообщения:
    8
    Здравствуйте, прошу помощи у знающих!
    Начала изучать возможности ассемблеровских вставок в Си. Пересмотрела много материала по этому вопросу, но так и не смогла найти ответ: как можно найти символ с наибольшем кодом ASCII в заранее веденной строке (на СИ) и вывести на экран этот символ с кодом с помощью ассемблера. Заранее спасибо!

    Код (Text):
    1. #include<stdio.h>
    2. #include<string.h>
    3. #include<conio.h>
    4. #include<iostream.h>
    5.  
    6. char *asmfunc(char *S, int n)   // функция нахождения символа с      
    7.                                                //максимальным кодом ASCII в  
    8.                                                      //строке S, n- длина строки
    9.  
    10. {
    11.  char *r = 0;
    12.  
    13. L0:
    14.  asm {  
    15.   mov SI,S;                // заносим в SI строку S
    16.   mov DL,n;               // заносим в DL длину строки
    17.  }
    18.  
    19. L1:
    20.  asm {
    21.   mov AL,0;       //  проверка на
    22.   add AL,[SI];   // конец строки, если конец, то уходим на L3
    23.   je L3;
    24.    }
    25.  
    26. ……. Не знаю что делать для того чтобы организовать поиск символа с наиб кодом
    27.  
    28. L2:
    29.  asm mov r, ….;    // необходимо вывести символ с наибольшим кодом в строке
    30.  
    31.  
    32. L3:
    33.  return r;
    34. }
    35.  
    36.  
    37.  
    38. void main ()
    39. {
    40. char ss[200],sim;
    41. char *r;
    42. int i, och,n;
    43.  
    44. asm {                
    45.   mov AH, 0;
    46.   mov AL, 2;
    47.   int 10H;
    48.   }
    49.  
    50. printf ("\n vvedite text s tochkoi: \n");      // ввод строки
    51.  
    52. for (i=0; ((sim=getchar()) !='.'); i++) ss[i]=sim;
    53. ss[i]='\0';
    54.  
    55. n=strlen(ss);
    56. r=asmfunc(ss,n);
    57.  
    58.  
    59. //////////////////////povtor programmy    
    60.  cout << "\n\n ochisit akran vvedite 1 ili 0 pov=:";
    61. cin >> och;
    62.  
    63. if (och==1)
    64. { asm {
    65.   mov AH, 0;
    66.   mov AL, 2;
    67.   int 10H;
    68.   }
    69. }
    70.  
    71.  getch ();
    72. }
     
  2. Alisia

    Alisia New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2009
    Сообщения:
    8
    Прошу прощения, создала не в том разделе. необходимо было в WASM.BEGINNERS. Как перевести в другой раздел?
     
  3. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Alisia
    Похоже это даже не в BEGINNERS, а в "Студентам с вопросами о лабораторных работах сюда".

    Если же это искреннее желание научиться то для начала стоит взять компилятор посовременнее - тот древний ДОСовский вряд-ли у кого найдётся в рабочем состоянии, а в более современном - под windows используется другая система комманд ассемблера (32 а не 16 разрядная).

    Впрочем имхо даже в разделе для лаб ответ маловероятен по той-же причине - без компилятора под рукой код не проверишь, а там ещё и морально устаревшую систему комманд вспоминать надо ;)
     
  4. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Надо было сразу написать, какая платформа, какая ОС и какой компилятор.
     
  5. Alisia

    Alisia New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2009
    Сообщения:
    8
    ОС - Windows Xp, работаю в Borland C++ 3.1
     
  6. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Alisia
    Ошибаешься :)) программа написанная на Borland C++ 3.1 работает не на ОС - Windows Xp, а в ДОС эмуляторе встроенном в эту ОС ;). Поэтому и асм 16разрядный и системные сервисы у тебя ДОСовские, а не виндовые.
    Была бы задачка на 32 разрядный асм под win, я бы помог, а с ДОС возится неохота и антикварный Borland C++ 3.1 ради этого устанавливать лень.
     
  7. Alisia

    Alisia New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2009
    Сообщения:
    8
    Нуу поожалуйстаа :))))
     
  8. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    Размер строки там вроде не требуется. Общий принцип: первый символ приминается за максимум и затем если другой максимум найден до конца строки - перезаписываем код символа и его смещение.

    Что-то в такой манере:
    Код (Text):
    1. char* FindMaxAsciiCode (char* s)
    2. {
    3.     char chMax;
    4.     int iMaxOffset;
    5.     //
    6.     // Load string address and
    7.     // assume that first character has
    8.     // maximum ASCII code for now.
    9.     //
    10.     _asm push es
    11.     _asm les si, s
    12.     _asm xor cx, cx
    13.     _asm mov iMaxOffset, cx   // iMaxOffset=0
    14.     _asm mov al, es:[si]
    15.     _asm mov chMax, al
    16.     //
    17.     // Load characters in loop and
    18.     // compare them to 'chMax'.
    19.     //
    20.     LOAD_NEXT_CHAR:
    21.     _asm inc si
    22.     _asm inc cx
    23.     _asm mov al, es:[si]
    24.     //
    25.     // Check if end of string is reached?
    26.     //
    27.     _asm test al, al
    28.     _asm jz END_OF_STRING
    29.     //
    30.     // Check if character in AL is larger than 'chMax'?
    31.     //
    32.     _asm cmp al, chMax
    33.     _asm jle LOAD_NEXT_CHAR
    34.     //
    35.     // We found a larger character than before.
    36.     // We need to remember its offset and character value.
    37.     //
    38.     _asm mov iMaxOffset, cx
    39.     _asm mov chMax, al
    40.     //
    41.     // Go back for more characters
    42.     //
    43.     _asm jmp LOAD_NEXT_CHAR
    44.  
    45.     END_OF_STRING:
    46.     _asm pop si
    47.  
    48.     return s + iMaxOffset;
    49. }
    50.  
    51. int main ()
    52. {
    53.     char* psMax = FindMaxAsciiCode ("dfkJHKHasdhsa:gffd;hdjKJHH63hh-=k");
    54.     //
    55.     // psMax will point to "sdhsa:gffd;hdjKJHH63hh-=k".
    56.     //
    57.     return 0;
    58. }
     
  9. Alisia

    Alisia New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2009
    Сообщения:
    8
    Попробывала запустить в Borland C++ - результата не показывает:dntknw:((( Хотя проходит все без ошибок. У меня еще есть Visiol Studio. А там ошибки выдает((
    Подскажите, пожалуйста, что я делаю не так.

     
  10. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Alisia
    Visual Studio какая? 6? 2005? 2008? или тоже древняя под ДОС? Если современная то конечно выдаёт ошибки как раз потому, что там ассемблер другой и не только он.
     
  11. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Alisia
    И объясни наконец это лаба котрую нужно сделать именно на Borland C++ 3.1 или ты для себя разбираешься и современный компилятор тебе вполне подойдёт?
     
  12. Alisia

    Alisia New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2009
    Сообщения:
    8
    Да. Это конечно же лаба, но в которой я хочу разобраться))) по заданию стоит Borland C++ 3.1. Но в принципе могу постараться разобраться и в другом компиляторе. visual studio 2008.

     
  13. redcat

    redcat New Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    62
    А добавить самостоятельно вывод результата не судьба printf("%c", psMax[0]);.
     
  14. Alisia

    Alisia New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2009
    Сообщения:
    8
    Да. Действительно, это от радости, теперь работает))) но результат не правильный(( Выводится только первый символ, а необходимо чтобы выводился символ с наибольшим кодом.
     
  15. redcat

    redcat New Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    62
    Функция char* FindMaxAsciiCode(char* s), по логике, должна возвращать указатель на требуемый (с макс. кодом) символ в строке, а уж что она действительно возращает разбирайтесь. Вы же хотели разобраться. Обратите внимание на команду проверки, подумайте, почему всегда первый символ выводится...
     
  16. Alisia

    Alisia New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2009
    Сообщения:
    8
    Да. Спасибо. Постараюсь разобраться.
     
  17. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Alisia
    Код (Text):
    1. __declspec(naked)
    2. char __fastcall FindMaxChar(char const *p, int n)
    3. {
    4.     // ecx = p, edx = n
    5.     __asm
    6.     {
    7.         push ebx
    8.         xor eax, eax    // в eax у нас будет результат, а пока что eax = 0
    9.                        
    10.         // начнём с конца строки символов (edx используем как индекс текущего символа)
    11.         jmp prevChar        // но на данный момент edx указывает на "послепоследний" символ в строке,
    12.                             // поэтому сразу переходим к предыдущему символу
    13.     handleChar:
    14.         movzx ebx, BYTE PTR [ecx+edx] // загружаем текущий символ в ebx
    15.         cmp eax, ebx    // сравниваем его с претендентом на результат
    16.  
    17.         cmovb eax, ebx  // если он оказался больше, то сам становится претендентом:
    18.                         // eax = ebx если eax < ebx (cmov проверяет флаги, выставленные предыдущим cmp)
    19.     prevChar:
    20.         dec edx         // переходим к предыдущему символу (уменьшаем индекс): edx = edx - 1.
    21.         jge handleChar  // Если edx >= 0 (мы не вывалились за начало строки) переходим к обработке символа
    22.         pop ebx
    23.         ret             // возвращаем результат
    24.     }
    25. }
     
  18. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Alisia
    Вот полный рабочий вариант для msvc 2008.
    Два варианта поиска на асме (второй более "продвинутый" закомментирован).
    И два варианта вывода результата на экран (через стандартную CRT библиотеку и через системные функции win api)
    Для но если для выбора максимального символа в строке асм вставка годится (как учебная задача) то вызов функций вывода на экран из ассемблерной вставки в С программе извращение то ещё. Это безобразие очень сильно зависит от реализации компилятора и даже от его настройки (при статической и динамической линковке CRT способ вызова её функций из асм вставки отличается).
    Результат выводится на экран 4 раза - два раза из асм вставок и два раза средствами С.

    ЗЫ: Перенести это 1:1 в Борлад 3.1 не получится, т.к. там и асм другой и вызов системных сервисов тоже.

    Код (Text):
    1. #include <stdio.h>
    2. #include <conio.h>
    3. #include <tchar.h>
    4. #include <windows.h>
    5.  
    6. int _tmain(int argc, _TCHAR* argv[])
    7. {
    8.     HANDLE hStdout, hStdin; // Handle консоли для вывода на экран
    9.     // Строковые константы:
    10.     LPCSTR lpszPrompt1 = "\nInput testing string with point and press Enter\n";
    11.     LPCSTR lpszMaxChar = "\nChar with max code \"%c\" (hex code 0x%X)\n";
    12.     DWORD cWritten, sizeString;
    13.     char szString[1024];    // буфер под строку
    14.     char szTmpStr[1024];    // буфер под временную строку
    15.     char currentChar, maxChar;
    16.  
    17.     // Определить Handle консоли для вывода на экран
    18.     hStdin = GetStdHandle(STD_INPUT_HANDLE);
    19.     hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    20.     // Приглашение ввести текстовую строку с точкой (завершение строки Enter)
    21.     WriteFile(hStdout, lpszPrompt1, strlen(lpszPrompt1), &cWritten, 0);
    22.  
    23.     // ввод строки средствами С
    24.     szString[0] = 0;
    25.     sizeString = 0;
    26.     do {
    27.         currentChar = _getch();
    28.         szString[sizeString] = currentChar;
    29.         // самодельное эхо лучше чем _getche (понимает русские буквы)
    30.         WriteFile(hStdout, &szString[sizeString], 1, &cWritten, 0);
    31.         sizeString++;
    32.     } while (currentChar != 13);    // завершить ввод строки по Enter
    33.     WriteFile(hStdout, "\n", 1, &cWritten, 0);  // перевод строки на консоли
    34.  
    35.     __asm {
    36.         // Поиск символа с максимальным кодом вариант 1:
    37.         // ( с условным переходом )
    38.             lea esi, szString       // адрес тестируемой строки
    39.             mov ecx, sizeString     // размер тестируемой строки
    40.             sub ecx, 1              // проверка на пустую строку
    41.             jbe emptyString
    42.             xor eax, eax            // обнулить сравниваемый символ
    43.             loop_1:
    44.                 cmp al, [esi + ecx]
    45.                 jnb skip_1
    46.                     mov al, [esi + ecx]
    47.                 skip_1:
    48.                 sub   ecx, 1
    49.             jnb loop_1
    50.             mov maxChar, al
    51.  
    52.         // Поиск символа с максимальным кодом вариант 2:
    53.         // ( безбранчевый )
    54. /*          lea esi, szString       // адрес тестируемой строки
    55.             mov ecx, sizeString     // размер тестируемой строки
    56.             sub ecx, 1              // проверка на пустую строку
    57.             jb emptyString
    58.             xor eax, eax            // обнулить сравниваемый символ
    59.         loop_2:
    60.                 cmp    al, [esi + ecx]
    61.                 cmovb eax, [esi + ecx]  // условное присвоение
    62.                 and   eax, 0xFF     // маска байта после условного присвоения
    63.                 sub   ecx, 1
    64.             jnz loop_2
    65.             mov maxChar, al
    66. */
    67.             // ==========================================
    68.             // Вывод результата средствами библиотеки CRT
    69.             movzx eax, maxChar
    70.             push eax            // код символа
    71.             push eax            // сам символ
    72.             push lpszMaxChar    // строка с комментариями вывода
    73.             // Вариант для динамической линковки CRT (ключ /MD)
    74.             lea eax, printf     // вывод на консоль с помощью CRT
    75.             call [eax]
    76.                 // Вариант для статической линковки CRT (ключ /MT)
    77. //          call printf    
    78.             add esp, 3*4    // очистка стека после функции в С стиле
    79.  
    80.  
    81.             // ==========================================
    82.             // Вывод результата средствами ОС (Win API)
    83.             // (предварительный вывод во временную строку)
    84.             movzx eax, maxChar
    85.             push eax                // код символа
    86.             push eax                // сам символ
    87.             push lpszMaxChar        // строка с комментариями вывода
    88.             lea eax, szTmpStr       // временная строка
    89.             push eax
    90.             lea eax, wsprintfA      // вывод во временную строку
    91.             call [eax]
    92.             add esp, 4*4    // очистка стека после функции в С стиле
    93.            
    94.             // (вывод временной строки на консоль)
    95.             push 0
    96.             lea ecx, cWritten   // служебная переменная
    97.             push ecx
    98.             push eax    // размер временной строки (в eax после функции wsprintf)
    99.             lea ecx, szTmpStr       // временная строка
    100.             push ecx
    101.             push hStdout            // Handle консоли
    102.             lea eax, WriteFile      // вывод на консоль
    103.             call [eax]
    104.     }   // Конец ассемблерной вставки
    105.  
    106.     // ==========================================
    107.     //  Вывод результата средствами CRT из С
    108.     printf(lpszMaxChar, maxChar, maxChar & 0xFF);
    109.  
    110.     //  Вывод результата средствами ОС из С
    111.     int tmpSize = wsprintfA(szTmpStr, lpszMaxChar, maxChar, maxChar & 0xFF);
    112.     WriteFile(hStdout, szTmpStr, tmpSize, &cWritten, 0);
    113.  
    114.     _getch();
    115.     return 0;
    116.  
    117.     //  Сообщение о пустой строке
    118. emptyString:
    119.     printf("The string is empty/n");
    120.     _getch();
    121.     return 0;
    122. }
     
  19. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    Alisia
    А проблема - в модели компиляции. Есть разные модели компиляции в 16-ти битном С: TINY, SMALL, LARGE, MEDIUM, HUGE, COMPACT. У меня установлена только LARGE на моей версии TC++ 3.1. Проблема возникает потому что адрес имеет разный размер. Например, в LARGE модели - адрес включает сегмент и смещение (поэтому: "LES SI, ..."), а в TINY, к примеру - только смещение, так как сегмент всегда тот же. Попробуй строить код (который я прислал) в модели LARGE и всё заработает. В моделях, где сегмент тот же, надо загружать адрес в регистр SI по другому.
     
  20. redcat

    redcat New Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    62
    Всегда первый символ