Жанр: Учеба
Ассемблер и программирование для IBM PC
...жимого
MUL MULTPLR ; * слово-1 множителя
ADD PRODUCT+4,AX ;Сложить с предыдущим
ADC PRODUCT+6,DX
ADC PRODUCT,00 ;Прибавить перенос
MOV AX,MULTCND ;Слово-1 множимого
MUL MULTPLR+2 ; * слово-2 множителя
ADD PRODUCT+4,AX ;Сложить с предыдущим
ADC PRODUCT+6,DX
ADC PRODUCT,00 ;Прибавить перенос
MOV AX,MULTCND ;Слово-1 множимого
MUL MULTPLR ; * слово-1 множителя
ADD PRODUCT+2,AX ;Сложить с предыдущим
ADC PRODUCT,DX
RET
F10XMUL ENDP
; Очистка области результата:
; ----------------------------------------
Z10XMUL PROC
MOV PRODUCT,0000
MOV PRODUCT+2,0000
MOV PRODUCT+4,0000
MOV PRODUCT+6,0000
RET
Z10XMUL ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.12.4. Многословное умножение.
У м н о ж е н и е "д в о й н о г о с л о в а н а д в о й н о е
с л о в о". Умножение двух двойных слов включает следующие четыре операции
умножения:
Множимое Множитель
слово 2 х слово 2
слово 2 х слово 1
слово 1 х слово 2
слово 1 х слово 1
Каждое произведение в регистрах DX и AX складывается с соответствующим
словом в окончательном результате. Пример такого умножения приведен в
процедуре F10XMUL на рис.12.4. Множимое MULTCND содержит шест.3206 2521,
множитель MULTPLR - шест.6400 0A26. Результат заносится в область PRODUCT,
состоящую из четырех слов.
Хотя логика умножения двойных слов аналогична умножению двойного
слова на слово, имеется одна особенность, после пары команд сложения
ADD/ADC используется еще одна команда ADC, которая прибавляет 0 к значению
в поле PRODUCT. Это необходимо потому, что первая команда ADC сама может
вызвать перенос, который последующие команды могут стереть. Поэтому вторая
команда ADC прибавит 0, если переноса нет, и прибавит 1, если перенос
есть. Финальная пара команд ADD/ADC не требует дополнительной команды ADC,
так как область PRODUCT достаточно велика для генерации окончательного
результата и переноса на последнем этапе не будет.
Окончательный результат 138A 687C 8E5C CCE6 получится в поле PRODUCT
в обратной записи байт в словах. Выполните трассировку этого примера с
помощью отладчика DEBUG.
СДВИГ РЕГИСТРОВОЙ ПАРЫ DX:AX
________________________________________________________________
Следующая подпрограмма может быть полезна для сдвига содержимого
регистровой пары DX:AX вправо или влево. Можно придумать более эффективный
метод, но данный пример представляет общий подход для любого числа циклов
(и, соответственно, сдвигов) в регистре CX. Заметьте, что сдвиг единичного
бита за разрядную сетку устанавливает флаг переноса.
Сдвиг влево на 4 бита
MOV CX,04 ;Инициализация на 4 цикла
C20: SHL DX,1 ;Сдвинуть DX на 1 бит влево
SHL AX,1 ;Сдвинуть AX на 1 бит влево
ADC DX,00 ;Прибавить значение переноса
LOOP C20 ;Повторить
Сдвиг вправо на 4 бита
MOV CX,04 ;Инициализация на 4 цикла
D20: SHR AX,1 ;Сдвинуть AX на 1 бит вправо
SHR DX,1 ;Сдвинуть DX на 1 бит вправо
JNC D30 ;Если есть перенос,
OR AH,10000000B ; то вставить 1 в AH
D30: LOOP D20 ;Повторить
Ниже приведен более эффективный способ для сдвига влево, не требующий
организации цикла. В этом примере фактор сдвига записывается в регистр CL.
Пример написан для сдвига на 4 бита, но может быть адаптирован для других
величин сдвигов:
MOV CL,04 ;Установить фактор сдвига
SHL DX,CL ;Сдвинуть DX влево на 4 бита
MOV BL,AH ;Сохранить AH в BL
SHL AX,CL ;Сдвинуть AX влево на 4 бита
SHL BL,CL ;Сдвинуть BL вправо на 4 бита
OR DL,BL ;Записать 4 бита из BL в DL
ДЕЛЕНИЕ
________________________________________________________________
Операция деления для беззнаковых данных выполняется командой DIV, a
для знаковых - IDIV. Ответственность за подбор подходящей команды лежит на
программисте. Существуют две основные операции деления:
Д е л е н и е "с л о в а н а б а й т". Делимое находится в регистре
AX, а делитель - в байте памяти или а однобайтовом регистре. После деления
остаток получается в регистре AH, а частное - в AL. Так как однобайтовое
частное очень мало (максимально +255 (шест.FF) для беззнакового деления и
+127 (шест.7F) для знакового), то данная операция имеет ограниченное
использование.
| AX | | AH | AL |
До деления: |Делимое| После: |Остаток|Частное|
Д е л е н и е "д в о й н о г о с л о в а н а с л о в о". Делимое
находится в регистровой паре DX:AX, а делитель - в слове памяти или а
регистре. После деления остаток получается в регистре DX, а частное в
регистре AX. Частное в одном слове допускает максимальное значение +32767
(шест.FFFF) для беззнакового деления и +16383 (шест.7FFF) для знакового.
| DX || AX | | AH || AL |
До деления: |Ст.часть||Мл.часть| После: |Остаток||Частное|
| Делимое |
В единственном операнде команд DIV и IDIV указывается делитель. Рассмотрим
следующую команду:
DIV DIVISOR
Если поле DIVISOR определено как байт (DB), то операция предполагает
деление слова на байт. Если поле DIVISOR определено как слово (DW), то
операция предполагает деление двойного слова на слово.
При делении, например, 13 на 3, получается результат 4 1/3. Частное
есть 4, а остаток - 1. Заметим, что ручной калькулятор (или программа на
языке BASIC) выдает в этом случае результат 4,333.... Значение содержит
целую часть (4) и дробную часть (,333). Значение 1/3 и 333... есть дробные
части, в то время как 1 есть остаток от деления.
Беззнаковое деление: Команда DIV
----------------------------------
Команда DIV делит беззнаковые числа. На рис.12.5 в процедуре D10DIV
дано четыре примера деления: слово на байт, байт на байт, двойное слово на
слово и слово на слово. Первый пример команды DIV делит шест.2000 (8092)
на шест.80 (128). В результате остаток 00 получается в регистре AH, а
частное шест.40 (64) - в регистре AL.
Второй пример команды DIV выполняет прежде расширение байта BYTE1 до
размеров слова. Так как здесь предполагается беззнаковая величина, то в
примере левый бит регистра AH равен нулю. В результате деления остаток -
шест.12 получается в регистре AH, а частное шест.05 - в регистре AL.
Третий пример команды DIV генерирует остаток шест.1000 в регистре DX
и частное шест.0080 в регистре AX.
В четвертом примере команды DIV сначала выполняется расширение слова
WORD1 до двойного слова в регистре DX. После деления остаток шест.0000
получится в регистре DX, а частное шест.0002 - в регистре AX.
__________________________________________________________________________
page 60,132
TITLE EXDIV (COM) Пример операций DIV и IDIV
CODESG SEGMENT PARA 'Code'
ORG 100H
BEGIN: JMP SHORT MAIN
; ---------------------------------------------
BYTE1 DB 80H ;Data items
BYTE2 DB 16H
WORD1 DW 2000H
WORD2 DW 0010H
WORD3 DW 1000H
; ---------------------------------------------
MAIN PROC NEAR ;Основная процедура
CALL D10DIV ;Вызов подпрограммы DIV
CALL E10IDIV ;Вызов подпрограммы IDIV
MAIN ENDP
; Примеры с командой DIV:
; ---------------------------------------------
D10DIV PROC
MOV AX,WORD1 ;Слово / байт
DIV BYTE1 ; остаток:частное в AH:AL
MOV AL,BYTE1 ;Байт / байт
SUB AH,AH ; расширить делимое в AH
DIV BYTE3 ; остаток:частное в AH:AL
MOV DX,WORD2 ;Двойное слово / слово
MOV AX,WORD3 ; делимое в DX:AX
DIV WORD1 ; остаток:частное в DX:AX
MOV AX,WORD1 ;Слово / слово
SUB DX,DX ; расширить делимое в DX
DIV WORD3 ; остаток:частное в DX:AX
RET
D10DIV ENDP
; Примеры с командой IDIV:
; ---------------------------------------------
E10IDIV PROC
MOV AX,WORD1 ;Слово / байт
IDIV BYTE1 ; остаток:частное в AH:AL
MOV AL,BYTE1 ;Байт / байт
CBW ; расширить делимое в AH
IDIV BYTE3 ; остаток:частное в AH:AL
MOV DX,WORD2 ;Двойное слово / слово
MOV AX,WORD3 ; делимое в DX:AX
IDIV WORD1 ; остаток:частное в DX:AX
MOV AX,WORD1 ;Слово / слово
CWD ; расширить делимое в DX
IDIV WORD3 ; остаток:частное в DX:AX
RET
E10DIV ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.12.5. Беззнаковое и знаковое деление.
Знаковое деление: Команда IDIV
--------------------------------
Команда IDIV (Integer DIVide) выполняет деление знаковых чисел. На
рис.12.5 в процедуре E10IDIV используются те же четыре примера деления,
что и в процедуре D10DIV, но вместо команд DIV записаны команды IDIV.
Первый пример команды IDIV делит шест.2000 (положительное число) на
шест.80 (отрицательное число). Остаток от деления - шест. 00 получается в
регистре AH , а частное - шест. C0 (-64) - в регистре AL. Команда DIV,
используя те же числа, генерирует частное +64.
Шестнадцатиричные результаты трех остальных примеров деления
приведены ниже:
Пример команды IDIV Остаток Частное
2 EE (-18) FB (-5)
3 1000 (4096) 0080 (128)
4 0000 0002
Только в примере 4 вырабатывается такой же результат, что и для команды
DIV. Таким образом, если делимое и делитель имеют одинаковый знаковый бит,
то команды DIV и IDIV генерируют одинаковый результат. Но, если делимое и
делитель имеют разные знаковые биты, то команда DIV генерирует
положительное частное, а команда IDIV - отрицательное частное. Можно
обнаружить это, используя отладчик DEBUG для трассировки этих примеров.
Повышение производительности. При делении на степень числа 2 (2, 4, и
т.д.) более эффективным является сдвиг вправо на требуемое число битов. В
следующих примерах предположим, что делимое находится в регистре AX:
Деление на 2: SHR AX,1
Деление на 8: MOV CL,3
SHR AX,CL
Переполнения и прерывания
---------------------------
Используя команды DIV и особенно IDIV, очень просто вызвать
переполнение. Прерывания приводят (по крайней мара в системе, используемой
при тестировании этих программ) к непредсказуемым результатам. В операциях
деления предполагается, что частное значительно меньше, чем делимое.
Деление на ноль всегда вызывает прерывание. Но деление на 1 генерирует
частное, которое равно делимому, что может также легко вызвать прерывание.
Рекомендуется использовать следующее правило: если делитель - байт,
то его значение должно быть меньше, чем левый байт (AH) делителя: если
делитель - слово, то его значение должно быть меньше, чем левое слово (DX)
делителя. Проиллюстрируем данное правило для делителя, равного 1:
Операция деления: Делимое Делитель Частное
Слово на байт: 0123 01 (1)23
Двойное слово на слово: 0001 4026 0001 (1)4026
В обоих случаях частное превышает возможный размер. Для того чтобы
избежать подобных ситуаций, полезно вставлять перед командами DIV и IDIV
соответствующую проверку. В первом из следующих примеров предположим, что
DIVBYTE - однобайтовый делитель, а делимое находится уже в регистре AX. Во
втором примере предположим, что DIVWORD - двухбайтовый делитель, а делимое
находится в регистровой паре DX:AX.
Слово на байт Двойное слово на байт
CMP AH,DIVBYTE CMP DX,DIVWORD
JNB переполнение JNB переполнение
DIV DIVBYTE DIV DIVWORD
Для команды IDIV данная логика должна учитывать тот факт, что либо
делимое, либо делитель могут быть отрицательными, а так как сравниваются
абсолютные значения, то необходимо использовать команду NEG для временного
перевода отрицательного значения в положительное.
Деление вычитанием
--------------------
Если частное слишком велико, то деление можно выполнить с помощью
циклического вычитания. Метод заключается в том, что делитель вычитается
из делимого и в этом же цикле частное увеличивается на 1. Вычитание
продолжается, пока делимое остается больше делителя. В следующем примере,
делитель находится в регистре AX, а делимое - в BX, частное вырабатывается
в CX:
SUB CX,CX ;Очистка частного
C20: CMP AX,BX ;Если делимое " делителя,
JB C30 ; то выйти
SUB AX,BX ;Вычитание делителя из делимого
INC CX ;Инкремент частного
JMP C20 ;Повторить цикл
С30: RET ;Частное в CX, остаток в AX
В конце подпрограммы регистр CX будет содержать частное, а AX -
остаток. Пример умышленно примитивен для демонстрации данной техники
деления. Если частное получается в регистровой паре DX:AX, то необходимо
сделать два дополнения:
1. В метке C20 сравнивать AX и BX только при нулевом DX.
2. После команды SUB вставить команду SBB DX,00.
П р и м е ч а н и е: очень большое частное и малый делитель могут
вызвать тысячи циклов.
ПРЕОБРАЗОВАНИЕ ЗНАКА
________________________________________________________________
Команда NEG обеспечивает преобразование знака двоичных чисел из
положительного в отрицательное и наоборот. Практически команда NEG
устанавливает противоположные значения битов и прибавляет 1. Примеры:
NEG AX
NEG BL
NEG BINAMT ;(байт или слово в памяти)
Преобразование знака для 35-битового (или большего) числа включает
больше шагов. Предположим, что регистровая пара DX:AX содержит 32-битовое
двоичное число. Так как команда NEG не может обрабатывать два регистра
одновременно, то ее использование приведет к неправильному результату. В
следующем примере показано использование команды NOT:
NOT DX ;Инвертирование битов
NOT AX ;Инвертирование битов
ADD AX,1 ;Прибавление 1 к AX
ADC DX,0 ;Прибавление переноса к DX
Остается одна незначительная проблема: над числами, представленными в
двоичном формате, удобно выполнять арифметические операции, если сами
числа определены в программе. Данные, вводимые в программу с дискового
файла, могут также иметь двоичный формат. Но данные, вводимые с
клавиатуры, представлены в ASCII-формате. Хотя ASCII-коды удобны для
отображения и печати, они требуют специальных преобразований в двоичный
формат для арифметических вычислений. Но это уже тема следующей главы.
ПРОЦЕССОРЫ INTEL 8087 И 80287 ДЛЯ ОБРАБОТКИ ЧИСЛОВЫХ ДАННЫХ
________________________________________________________________
Системная плата компьютера содержит пустое гнездо, зарезервированное
для числового процессора Intel 8087 (или 80287). Сопроцессор 8087
действует совместно с 8088, а сопроцессор 80287 действует совместно с
80286. Каждый сопроцессор имеет собственный набор команд и средства для
операций с плавающей запятой для выполнения экспоненциальных,
логарифмических и тригонометрических функций. Сопроцессор содержит восемь
80-битовых регистров с плавающей запятой, которые могут представить
числовые значения до 10 в 400 степени. Математические вычисления в
сопроцессоре выполняются примерно в 100 раз быстрее, чем в основном
процессоре.
Основной процессор выполняет специальные операции и передает числовые
данные в сопроцессор, который выполняет необходимые вычисления и
возвращает результат. Для ассемблирования с помощью транслятора MASM,
необходимо добавлять параметр /E или /R, например, MASM /R.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ
________________________________________________________________
- Будьте особенно внимательны при использовании однобайтовых
регистров. Знаковые значения здесь могут быть от -128 до +127.
- Для многословного сложения используйте команду ADC для учета
переносов от предыдущих сложений. Если операция выполняется в цикле, то
используя команду CLC, установите флаг переноса в 0.
- Используйте команды MUL или DIV для беззнаковых данных и команды
IMUL или IDIV для знаковых.
- При делении будьте осторожны с переполнениями. Если нулевой
делитель возможен, то обеспечьте проверку этой операции. Кроме того,
делитель должен быть больше содержимого регистра AH (для байта) или DX
(для слова).
- Для умножения или деления на степень двойки используйте сдвиг.
Сдвиг вправо выполняется командой SHR для беззнаковых полей и командой SAR
для знаковых полей. Для сдвига влево используются идентичные команды SHL и
SAL.
- Будьте внимательны при ассемблировании по умолчанию. Например, если
поле FACTOR определено как байт (DB), то команда MUL FACTOR полагает
множимое в регистре AL, а команда DIV FACTOR полагает делимое в регистре
AX. Если FACTOR определен как слово (DW), то команда MUL FACTOR полагает
множимое в регистре AX, а команда DIV FACTOR полагает делимое в
регистровой паре DX:AX.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ
________________________________________________________________
Все вопросы имеют отношение к следующим данным:
DATAX DW 0148H
DW 2316H
DATAY DW 0237H
DW 4052H
12.1. Закодируйте команды для сложения а) слова DATAX со словом
DATAY; б) двойного слова, начинающегося по адресу DATAX, с двойным словом
в DATAY.
12.2. Объясните действие следующих команд:
STC
MOV BX,DATAX
ADC BX,DATAY
12.3. Закодируйте команды для умножения (MUL): а) слова DATAX на
слово DATAY; б) двойного слова , начинающегося по адресу DATAX, на слово
DATAY.
12.4. Какой делитель, кроме нуля, вызывает ошибку переполнения?
12.5. Закодируйте команды для деления (DIV): а) слова DATAX на 23; б)
двойного слова, начинающегося по адресу DATAX, на слово DATAY.
12.6. Последний пример в разделе "Сдвиг регистровой пары DX:AX"
является более эффективным по сравнению с предыдущими примерами для сдвига
влево на четыре бита. Измените пример для сдвига вправо на четыре бита.
ГЛАВА 13 Арифметические операции II:
Обработка данных в форматах ASCII и BCD
__________________________________________________________________________
Ц е л ь: Рассмотреть ASCII и BCD форматы данных и дать сведения о
преобразованиях между этими форматами и двоичным форматом.
ВВЕДЕНИЕ
________________________________________________________________
Для получения высокой производительности компьютер выполняет
арифметические операции над числами в двоичном формате. Как показано в
гл.12, этот формат не вызывает особых трудностей, если данные определены в
самой программе. Во многих случаях новые данные вводятся программой с
клавиатуры в виде ASCII символов в десятичном формате. Аналогично вывод
информации на экран осуществляется в кодах ASCII. Например, число 23 в
двоичном представлении выглядит как 00010111 или шест.17; в коде ASCII на
каждый символ требуется один байт и число 25 в ASCII-коде имеет внутреннее
представление шест.3235.
Назначение данной главы - показать технику преобразования данных из
ASCII-формата в двоичный формат для выполнения арифметических операций и
обратного преобразования двоичных результатов в ASCII-формат для вывода на
экран или принтер. Программа, приведенная в конце главы , демонстрирует
большую часть материала гл.1 - 12.
При программировании на языках высокого уровня, таких как BASIC или
Pascal, для обозначения порядка числа или положения десятичной запятой
(точки) можно положиться на компилятор. Однако, компьютер не распознает
десятичную запятую (точку) в арифметических полях. Так как двоичные числа
не имеют возможности установки десятичной (или двоичной) запятой (точки),
то именно программист должен подразумевать и определить порядок
обрабатываемых чисел.
ASCII-ФОРМАТ
________________________________________________________________
Данные, вводимые с клавиатуры, имеют ASCII-формат, например, буквы
SAM имеют в памяти шестнадцатиричное представление 53414D, цифры 1234 -
шест.31323334. Во многих случаях формат алфавитных данных, например, имя
человека или описание статьи, не меняется в программе. Но для выполнения
арифметических операций над числовыми значениями, такими как
шест.31323334, требуется специальная обработка.
С помощью следующих ассемблерных команд можно выполнять
арифметические операции непосредственно над числами в ASCII-формате:
AAA (ASCII Adjust for Addition - коррекция для сложения ASCII-кода)
AAD (ASCII Adjust for Division - коррекция для деления ASCII-кода)
AAM (ASCII Adjust for Multiplication - коррекция для умножения ASCII-кода)
AAS (ASCII Adjust for Subtraction - коррекция для вычитания ASCII-кода)
Эти команды кодируются без операндов и выполняют автоматическую коррекцию
в регистре AX. Коррекция необходима, так как ASCII-код представляет так
называемый распакованный десятичный формат, в то время, как компьютер
выполняет арифметические операции в двоичном формате.
Сложение в ASCII-формате
--------------------------
Рассмотрим процесс сложения чисел 8 и 4 в ASCII-формате:
Шест. 38
--
Шест. 6C
Полученная сумма неправильна ни для ASCII-формата, ни для двоичного
формата. Однако, игнорируя левую 6 и прибавив 6 к правой шест.C: шест.C +
6 = шест.12 - получим правильный результат в десятичном формате.
Правильный пример слегка упрощен, но он хорошо демонстрирует процесс,
который выполняет команда AAA при коррекции.
В качестве примера, предположим, что регистр AX содержит шест.0038, а
регистр BX - шест.0034. Числа 38 и 34 представляют два байта в
ASCII-формате, которые необходимо сложить. Сложение и коррекция кодируется
следующими командами:
ADD AL,BL ;Сложить 34 и 38
AAA ;Коррекция для сложения ASCII-кодов
Команда AAA проверяет правую шест. цифру (4 бита) в регистре AL. Если эта
цифра находится между A и F или флаг AF равен 1, то к регистру AL
прибавляется 6, а к регистру AH прибавляется 1, флаги AF и CF
устанавливаются в 1. Во всех случаях команда AAA устанавливает в 0 левую
шест. цифру в регистре AL. Результат - в регистре AX:
После команды ADD: 006C
После команды AAA: 0102
Для того, чтобы выработать окончательное ASCII-представление,
достаточно просто поставить тройки на место левых шест. цифр:
OR AX,3030H ;Результат 3132
Все показанное выше представляет сложение однобайтовых чисел.
Сложение многобайтовых ASCII-чисел требует организации цикла, который
выполняет обработку справа налево с учетом переноса. Пример , показанный
на рис.13.1 складывает два трехбайтовых ASCII-числа в четырехбайтовую
сумму. Обратите внимание на следующее:
__________________________________________________________________________
TITLE ASCADD (COM) Сложение чисел в ASCII-формате
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
ORG 100H
BEGIN: JMP SHORT MAIN
; -----------------------------------------------
ASC1 DB '578' ;Элементы данных
ASC2 DB '694'
ASC3 DB '0000'
; -----------------------------------------------
MAIN PROC NEAR
CLC
LEA SI,AASC1+2 ;Адреса ASCII-чисел
LEA DI,AASC2+2
LEA BX,AASC1+3
MOV CX,03 ;Выполнить 3 цикла
A20:
MOV AH,00 ;Очистить регистр AH
MOV AL,[SI] ;Загрузить ASCII-байт
ADC AL,[DI] ;Сложение (с переносом)
AAA ;Коррекция для ASCII
MOV [BX],AL ;Сохранение суммы
DEC SI
DEC DI
DEC BX
LOOP A20 ;Циклиться 3 раза
MOV [BX],AH ;Сохранить перенос
RET
MAIN ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.13.1. Сложение в ASCII-формате.
- В программе используется команда ADC, так как любое сложение
может вызвать перенос, который должен быть прибавлен к следующему
(слева) байту. Команда CLC устанавливает флаг CF в нулевое состояние.
- Команда MOV очищает регистр AH в каждом цикле, так как команда
AAA может прибавить к нему единицу. Команда ADC учитывает переносы.
Заметьте, что использование команд XOR или SUB для очистки регистра
AH изменяет флаг CF.
- Когда завершается каждый цикл, происходит пересылка
содержимого регистра AH (00 или 01) в левый байт суммы.
- В результате получается сумма в виде 01020702. Программа не
использует команду OR после команды AAA для занесения левой тройки,
так как при этом устанавливается флаг CF, что изменит результат
команды ADC. Одним из решений в данном случае является сохранение
флагового регистра с помощью команды PUSHF, вып
...Поділитися у соцмережах