машинный код x86, 70 байт
60 89 d7 31 db 43 88 ce b2 fe 49 d1 e1 87 da 0f
c7 f0 24 7f 3c 22 72 f7 48 3c 79 74 f2 3c 59 74
ee aa 49 7c 1c 00 df 79 06 86 f7 42 43 eb f6 f6
c3 01 74 03 b0 0a aa 51 88 f9 b0 20 f3 aa 59 eb
cc c6 07 00 61 c3
Мой исполняемый код разобран:
0000003d <myheh>:
3d: 60 pusha
3e: 89 d7 mov %edx,%edi
40: 31 db xor %ebx,%ebx
42: 43 inc %ebx
43: 88 ce mov %cl,%dh
45: b2 fe mov $0xfe,%dl
47: 49 dec %ecx
48: d1 e1 shl %ecx
0000004a <myloop>:
4a: 87 da xchg %ebx,%edx
0000004c <myrand>:
4c: 0f c7 f0 rdrand %eax
4f: 24 7f and $0x7f,%al
51: 3c 22 cmp $0x22,%al
53: 72 f7 jb 4c <myrand>
55: 48 dec %eax
56: 3c 79 cmp $0x79,%al
58: 74 f2 je 4c <myrand>
5a: 3c 59 cmp $0x59,%al
5c: 74 ee je 4c <myrand>
5e: aa stos %al,%es:(%edi)
5f: 49 dec %ecx
60: 7c 1c jl 7e <mydone>
00000062 <mylab>:
62: 00 df add %bl,%bh
64: 79 06 jns 6c <myprint>
66: 86 f7 xchg %dh,%bh
68: 42 inc %edx
69: 43 inc %ebx
6a: eb f6 jmp 62 <mylab>
0000006c <myprint>:
6c: f6 c3 01 test $0x1,%bl
6f: 74 03 je 74 <myprint1>
71: b0 0a mov $0xa,%al
73: aa stos %al,%es:(%edi)
00000074 <myprint1>:
74: 51 push %ecx
75: 88 f9 mov %bh,%cl
77: b0 20 mov $0x20,%al
79: f3 aa rep stos %al,%es:(%edi)
7b: 59 pop %ecx
7c: eb cc jmp 4a <myloop>
0000007e <mydone>:
7e: c6 07 00 movb $0x0,(%edi)
81: 61 popa
82: c3 ret
Это функция, которая получает размер X в ecx и указатель на выходной буфер в edx.
Он заполняет выходной буфер последовательно байтами. Есть 2 * n - 1
итерации (равные количеству непробельных символов для вывода). На каждой итерации выполняется следующее:
- Генерация случайного числа
- Поиграть с номером, чтобы вписать его в диапазон; если это плохо, вернись и сгенерируй заново
- Распечатать случайный символ
- Вывести новую строку (каждую другую итерацию)
- Распечатать правильное количество пробелов
Преобразование из случайного числа в случайный символ не примечательно:
myrand:
rdrand eax;
and al, 7fh;
cmp al, 22h;
jb myrand;
dec eax;
cmp al, 'y';
je myrand;
cmp al, 'Y';
je myrand;
Интересной частью является подсчет количества мест. Он должен генерировать следующие числа (пример для N = 9):
7 1
5 2
3 3
1 4
3
1 2
3 1
5 0
7
Числа взяты поочередно из двух арифметических прогрессий. Первый идет вниз с шагом -2, а второй идет вверх с шагом 1. Когда первая прогрессия достигает -1 (в середине X), возникает сбой (-1 удаляется), а затем прогрессии меняют направление.
Прогрессии сохраняются в регистрах ebx
и edx
- старшие части bh
и dh
сохраняют текущий номер, а младшие - bl
и dl
сохраняют шаг. Чтобы чередовать прогрессии, код меняет регистры с xchg
.
Когда прогрессия достигает -1 (вокруг mylab
метки), она увеличивает оба регистра, переключая шаги с -2, 1
на -1, 2
. Это также меняет роли регистров, а затем меняет верхние части регистров.
В конце функции хранится нулевой байт, указывающий конец строки.