Skip to content

Latest commit

 

History

History
37 lines (32 loc) · 8.01 KB

Lecture 20.md

File metadata and controls

37 lines (32 loc) · 8.01 KB


Еще о фичах

foreach
Как раскрыть? v.begin(), v.end() не применим для массивов например. Выход простой — запилить внешнюю перегрузку std::begin(v), std::end(v), std::size(v)

Когда расширяешь язык, можно многое забыть

template<typename T>
std::vector<T>::const_iterator f(std::vector<T> const &v) {}

void g(std::vector<int> &v) { std::find(f(v), v.end(), 5) }

Не работает, ибо разные типы итераторов, поэтому потом добавили .cend(), .cbegin() и т.д.

Но забыли добавить std::cbegin(v) И т.д, хех (вроде в с++11)

Еще забыли в лямбдах разрешать move

[a]  {...}
[&a] {...}

Потом добавили [a = std::move(a)] {}, где инициализатором может быть все что угодно

Еще в initializer_list не предусмотрен move, если написать

string s;
std::vector<string> a = {"foo", "bar", std::move(s)}

то в итоге s скопируется сначала в лист, а потом в вектор — два копирования вместо мува, хыхы

Как работают динамические либы

.so загружается не всегда по одному адресу. Проблема — мы не можем в машинном коде знать адрес переменных. Для статики легко — просто смотрим на разницу адресов.

Можно попробовать хранить в регистре в какой адрес мы загрузились, но тогда надо аккуратно все перетирать регистры при вызове длл из длл (вроде), плюс может использоваться прослойка для вызова функции и иногда вместо адреса функции мы получим адрес прослойки

Можно хранить таблицу релокаций — просто загрузить программу, пройтись по всем внешним функциям, переправить адреса, но это замедляет старт программы (в винде вроде что-то такое, но они просто инкрементят на address - base_address). Еще проблема — если загрузилось в base_address, то шарится между всеми процессами, иначе у каждого процесса своя копия дллки.

В линухе есть GOT (global offset table) — чтобы не править всю программу собирается то, что зависит от адресов программы, и правим мы уже GOT. Но вот проблема — как обращаться к GOT’у? (используется для чего-то другого, хз для чего)

Еще один выход. У нас есть jmp, казалось бы для него такая же проблема с адресами? Нет, он использует относительный адрес, поэтому ему пофиг (и call тоже). Так а почему бы и память не читать относительно? На 64-битных системах появились такие команды, поэтому мы можем сгенерить код на относительных адресах (PIC (position independent code)).
А что делать с 32-битными системами?( В линуксе такой код генерится и для 32-бит, но обращение делается неэффективно. Делают call на некоторую функцию, которая возвращает адрес этой функции и зная относительные адреса херачим.

Когда запускаете программу — запускается не ваша программа, а динамический загрузчик (в линухе что-то вроде ld-linux.so) и ваша программа передается ему как аргумент. И в линухе просят “дайте мне кто-нибудь эту функцию”, а динамический загрузчик как-то выбирает из .so приоритеты.