fork download
  1. section .data
  2. ; Оголошуємо самі слова (рядки з нуль-термінатором)
  3. w1 db "Orange", 0
  4. w2 db "Apple", 0
  5. w3 db "Banana", 0
  6. w4 db "Apricot", 0
  7. w5 db "Cherry", 0
  8.  
  9. ; Масив вказівників (адрес) на ці слова. Сортувати будемо саме цей масив.
  10. ptr_array dq w1, w2, w3, w4, w5
  11.  
  12. ; Кількість слів
  13. len equ ($ - ptr_array) / 8
  14.  
  15. section .text
  16. global _start
  17.  
  18. _start:
  19. ; --- Передача параметрів через стек ---
  20. push ptr_array ; [rbp + 24] Адреса масиву вказівників
  21. push len ; [rbp + 16] Кількість слів
  22.  
  23. call bubble_sort ; Виклик процедури
  24.  
  25. add rsp, 16 ; Очищення стеку
  26.  
  27. ; --- Вихід ---
  28. mov rax, 60
  29. xor rdi, rdi
  30. syscall
  31.  
  32. ; ---------------------------------------------
  33. ; Процедура Bubble Sort для рядків
  34. ; ---------------------------------------------
  35. bubble_sort:
  36. push rbp
  37. mov rbp, rsp
  38.  
  39. mov rcx, [rbp + 16] ; RCX = кількість елементів (N)
  40. dec rcx ; N-1 проходів
  41. cmp rcx, 0
  42. jle .done
  43.  
  44. mov rbx, [rbp + 24] ; RBX = адреса масиву вказівників
  45.  
  46. .outer_loop:
  47. push rcx
  48. mov rdx, rcx ; RDX = лічильник внутрішнього циклу
  49. xor rsi, rsi ; RSI = індекс (0, 1, 2...)
  50.  
  51. .inner_loop:
  52. ; Отримуємо адреси двох сусідніх рядків
  53. ; [rbx + rsi*8] - адреса першого рядка
  54. ; [rbx + rsi*8 + 8] - адреса другого рядка
  55. mov rdi, [rbx + rsi*8] ; Аргумент 1 для порівняння
  56. mov rax, [rbx + rsi*8 + 8] ; Аргумент 2 (збережемо в RAX поки що)
  57.  
  58. ; Зберігаємо регістри перед викликом порівняння (System V ABI convention)
  59. push rsi
  60. push rdx
  61. push rcx
  62. push rbx
  63. push rax ; Кладемо адресу другого рядка в стек або передаємо через регістр
  64.  
  65. mov rsi, rax ; Аргумент 2 для порівняння
  66. call str_compare
  67. ; Результат в RAX: <0 якщо str1 < str2, >0 якщо str1 > str2
  68.  
  69. pop rax ; Відновлюємо (це була адреса 2-го рядка, вона вже не треба, просто чистимо стек)
  70. pop rbx
  71. pop rcx
  72. pop rdx
  73. pop rsi
  74.  
  75. cmp rax, 0
  76. jle .no_swap ; Якщо str1 <= str2, міняти не треба (алфавітний порядок)
  77.  
  78. ; --- Обмін вказівників ---
  79. ; Міняємо місцями адреси в масиві ptr_array, а не самі букви
  80. mov r8, [rbx + rsi*8] ; Завантажуємо вказівник 1
  81. mov r9, [rbx + rsi*8 + 8] ; Завантажуємо вказівник 2
  82. mov [rbx + rsi*8], r9 ; Записуємо 2 на місце 1
  83. mov [rbx + rsi*8 + 8], r8 ; Записуємо 1 на місце 2
  84.  
  85. .no_swap:
  86. inc rsi ; Наступна пара
  87. dec rdx
  88. jnz .inner_loop
  89.  
  90. pop rcx
  91. loop .outer_loop
  92.  
  93. .done:
  94. mov rsp, rbp
  95. pop rbp
  96. ret
  97.  
  98. ; ---------------------------------------------
  99. ; Процедура порівняння рядків (аналог strcmp)
  100. ; Вхід: RDI = адреса рядка 1, RSI = адреса рядка 2
  101. ; Вихід: RAX > 0, якщо рядок 1 "більший" (далі за алфавітом)
  102. ; RAX < 0, якщо рядок 1 "менший"
  103. ; RAX = 0, якщо рівні
  104. ; ---------------------------------------------
  105. str_compare:
  106. xor rax, rax
  107. .cmp_loop:
  108. mov al, byte [rdi]
  109. mov bl, byte [rsi]
  110.  
  111. cmp al, bl
  112. jne .diff_found ; Якщо букви різні, визначимо хто більший
  113.  
  114. test al, al ; Чи це кінець рядка (0)?
  115. jz .equal ; Якщо дійшли до кінця і всі рівні -> рядки рівні
  116.  
  117. inc rdi
  118. inc rsi
  119. jmp .cmp_loop
  120.  
  121. .diff_found:
  122. sub al, bl ; Віднімаємо коди ASCII
  123. movsx rax, al ; Розширюємо результат до 64 біт зі збереженням знаку
  124. ret
  125.  
  126. .equal:
  127. xor rax, rax
  128. ret
Success #stdin #stdout 0s 5320KB
stdin
Standard input is empty
stdout
Standard output is empty