−1
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
// вообще, есть одна говнистая особенность сишки:
// нельзя вернуть из функции массив хуйпойми какой длины, выделив память чисто на стеке
// Вот например:
char *a_ret (size_t len)
{
char *ret = alloca(len);
memset(ret, 'a', len);
return ret; // так нельзя
}
// т.е. надо делать как-нибудь вот так
char *a_ret (size_t len)
{
char *ret = malloc(len);
if (ret == NULL)
{
exit(ENOMEM);
}
memset(ret, 'a', len);
return ret;
}
Но это ж на самом-то деле говно какое-то. Дергать аллокаторы какие-то, ради каких-то мелких кусков байтиков.
Почему не сделать хуйни, чтоб вызываемая функция как бы приосталавливалась и просила ту функцию, которая ее вызывает, чтоб она вот такой-то alloca() сделала нужного размера в своем стекфрейме, а потом туда вот та вызванная функция байтики уже вхерачивала? Ну т.е. можно сделать отдельный свой стек для локальных переменных тех функций, которые должны уметь такую хуйню делать (т.е. просить вызвавшую их функцию "а сделай ка там себе alloca(123) и дай мне указатель, а я в него насру")
Вообще хуйня какая-то, сишка слишком сильно сковывает всякой своей хуйней, соглашениями вызовов, всякими ABI там. То ли дело ассемблер!
Запостил: j123123,
15 Мая 2019
j123123 15.05.2019 07:02 # +2
puxStackBuffer - Must point to a StackType_t array that has at least ulStackDepth indexes (see the ulStackDepth parameter above) - the array will be used as the task's stack, so must be persistent (not declared on the stack of a function).
Во всяких POSIX Threads и вендоговняном CreateThread нихуя такого нет - вы ему не можете ткнуть адрес куда он будет стеком своим срать, оно там за тебя его как-то аллоцирует. Не по-царски.
bormand 15.05.2019 09:50 # 0
Web_Monkey 15.05.2019 09:23 # +1
В ANS стандарт не включены слова для работы с указателями стека, но во многих системах они есть: rp0 rp@ sp0 sp@ и пр.:
http://gforth.org/manual/Stack-pointer-manipulation.html#Stack-pointer-manipulation
Web_Monkey 15.05.2019 09:26 # 0
Elvenfighter 15.05.2019 09:25 # +6
А если хочешь, в алоцированую на стеке память записывать извне -- передай укозатель на то, что хочешь скопировать. Если у тебя генератор -- укозатель на функцию.
guest8 15.05.2019 11:59 # −999
bormand 15.05.2019 12:11 # 0
guest8 15.05.2019 12:21 # −999
bormand 15.05.2019 12:54 # 0
guest8 15.05.2019 13:06 # −999
guest8 15.05.2019 13:10 # −999
Web_Monkey 15.05.2019 13:18 # 0
guest8 15.05.2019 13:24 # −999
bormand 15.05.2019 12:14 # +2
Дык в винапи давным-давно сделали подобную хуйню...
- зовёшь функцию с null'ом, она "приостанавливается" (возвращает управление) и говорит сколько надо байтов
- делаешь alloca/malloc/что там тебе удобнее
- зовёшь функцию ещё раз с этим буфером для "продолжения"
j123123 15.05.2019 19:08 # 0
Есть в крестоговне лямбды, вот такая хуйня:
это UB или не UB? На самом-то деле вообще хуй знает, учитывая что alloca не часть стандарта C++ и C
Но зато есть гнутое расширение https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html в котором хуйни с UB быть не должно
Теоретически, можно было б сделать особый вид alloca, который был бы справедлив только для тех функций, которые всегда инлайнятся, назвать этот alloca можно как-нибудь типа alloca_in_caller т.е. типа выдели на стеке в той функции, которая меня вызывала, и дай мне указатель на ту вот хуйню
bormand 15.05.2019 19:13 # +1
j123123 15.05.2019 19:18 # 0
bormand 15.05.2019 19:25 # +1
Вызывающий запоминает позицию в этом стеке. Вызываемый размещает в нём кучу строк и структур и возвращает их адреса. Вызывающий юзает эти структуры и откатывает позицию стека когда они ему больше не нужны.
gost 15.05.2019 19:26 # 0
j123123 16.05.2019 18:28 # 0
Тогда мне надо на каждый такой вызов функции делать какой-то говнобуфер и еще думать над тем, какой у него там будет размер максимальный. Ну и еще я могу передавать указатель на подобного рода функцию в некую другую функцию (callback) и тогда мне надо еще вместе с функцией передавать отдельным аргументом то, сколько максимум байтиков та функция может высрать. В общем хуйня какая-то.
Правильней было б придумать особое соглашение вызова. Вот например в GCC если функция возвращает через return некую структурку известного размера с кучей байтиков, то вызывающая функция резервирует у себя на стеке нужное количество байтов под эту структуру, а потом делает call. Ну т.е. стек выглядит так
Но можно свое соглашение вызова придумать, т.е. сначала будет все как обычно, вызываемая функция где-то там в стек срет своими локальными переменными, адрес возврата где надо т.е.:
Но в самом конце, когда надо хуйпоймикакой массивчик высрать в стек для другой функции, мы просто переписываем все локальные переменные в стеке этой хуйней, предварительно забэкапив адрес возврата и хуйнув куда-нибудь то, сколько байтиков мы насрали (можно в регистр)
Ну вот как-то так это можно было бы решить
j123123 17.05.2019 08:45 # 0
nemyx 17.05.2019 14:52 # 0
nemyx 17.05.2019 15:59 # 0
j123123 17.05.2019 21:17 # 0
gost 15.05.2019 12:29 # +2
А как? Если вызывающая функция сделает у себя alloca() — она затрёт стекфрейм вызванной функции. Даже если мы волшебным образом сделаем отдельный стек для локальных переменных (джвух rsp у нас нету, придётся ебаться со скрытыми глобальными thread_local переменными, м-м-м…), адрес возврата всё равно будет лежать в «стандартном» стеке.
Так что во всём виноваты прыщи «ассемблер x86» с его кривыми стекфреймами.
gost 15.05.2019 12:35 # +2
guest8 15.05.2019 12:39 # −999
bormand 15.05.2019 12:49 # +2
gost 15.05.2019 13:09 # +1
nemyx 15.05.2019 13:30 # +1
guest8 15.05.2019 13:35 # −999
nemyx 15.05.2019 13:37 # +2
guest8 15.05.2019 13:40 # −999
j123123 15.05.2019 19:26 # +1
MPA3uIII 15.05.2019 19:35 # −7
gost 15.05.2019 20:01 # +3
nemyx 15.05.2019 20:04 # +1
bormand 15.05.2019 20:05 # +4
Вверху можно будет хранить большие переменные. А внизу мелкие, с точностью до бита.
guest8 15.05.2019 20:07 # −999
Rooster 15.05.2019 20:10 # +1
Rooster 15.05.2019 20:15 # +1
bormand 15.05.2019 12:53 # +4
guest8 15.05.2019 13:09 # −999
gost 15.05.2019 13:15 # +2
nemyx 15.05.2019 13:58 # +2
Когда доходит дело до использования, то выясняется, что перед вызовом функции вызывающий код должен забекапить содержимое своих регистров, чтобы использовать эти регистры для передачи параметров в функцию. Для резервного копирования обычно используют... всё тот же стек. Итого получается, что вызывающий код вместо того, чтобы пушить передаваемые данные (как было при стековых соглашениях вроде pascal, cdecl), пушит собственные промежуточные данные.
gost 15.05.2019 14:44 # +1
А вот дебажить «fastcall» сложнее — в середине функции уже вряд ли получится узнать, какие были переданы аргументы, приходится ставить бряки на начало. То ли дело «cdecl»: промотал стек до конца стекфрейма, и все аргументы прекрасно видны.
bormand 15.05.2019 14:57 # 0
Поставь мне бряку в дампе :(
gost 15.05.2019 16:49 # 0
guest8 02.08.2019 04:31 # −999
guest8 02.08.2019 06:35 # −999
PACTPOBblu_nemyx 02.08.2019 12:30 # 0
bormand 15.05.2019 14:55 # +3
В худшем случае, если аргумент нужен после вызова, ты бекапишь его.
Но если аргумент уже поюзан и не нужен, а часто это так, то бекапить ничего не надо. Профит.
nemyx 15.05.2019 16:06 # 0
Довольно частая ситуация –— нужно вызвать функцию от кокококонстант. При «cdecl» я могу запушить непосредственную константу из кода, не трогая никаких регистров (кроме rsp и rip, разумеется). При «fastcall» мне придётся эту константу класть в регистр, а если этот регистр оказался подо что-то занят, мне придётся его бекапить.
Да, довольно часто регистры можно переназначить, чтобы бекапить ничего не требовалось, но удаётся переназначить не всегда. RCX всё-таки довольно часто используется как счётчик.
bormand 15.05.2019 17:26 # +2
nemyx 15.05.2019 17:36 # 0
guest8 15.05.2019 16:19 # −999
nemyx 15.05.2019 16:24 # 0
guest8 15.05.2019 16:26 # −999
gost 15.05.2019 16:52 # 0
Web_Monkey 15.05.2019 16:57 # +1
bormand 15.05.2019 17:12 # +1
Именно поэтому я за thumb-2. Да, ARM таки скатился в команды переменной длины.
guest8 15.05.2019 17:17 # −999
Rooster 15.05.2019 18:01 # 0
guest8 15.05.2019 18:02 # −999
bormand 15.05.2019 17:38 # +1
И что делать если пришло прерывание?
Блочить их пока всё не сохранится? Сохранять стейт во флаги (ARM так делает для ldmia)? Рестартить всю push'a с нуля после выхода из прерывания? Все варианты - полная жопа.
nemyx 15.05.2019 17:42 # 0
Web_Monkey 15.05.2019 17:16 # +1
Straiker 21.05.2019 01:11 # 0
guest8 21.05.2019 03:57 # −999
Rooster 21.05.2019 06:35 # 0
rOqpPEH 21.05.2019 12:59 # 0
guest8 15.05.2019 16:25 # −999
nemyx 15.05.2019 16:42 # 0
https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html
Можно насрать в область, примыкающую к области локальных переменных вызывающей функции, не выделяя память, и вернуть размер этой области, чтобы вызывающая функция после возврата сама сделала alloca.
Минус: выделять придётся чуть больше, чем нужно, ибо между локальными переменными и свободным куском ещё лежит адрес разврата, параметры, не поместившиеся в регистрах, резервные копии регистров и локальные переменные вызываемой функции. Эта область (адрес разврата + параметры) после возврата не будет нужна, но останется лежать мёртвым грузом.
Если лишняя память представляет проблему, то вызывающая функция может дефрагментировать память с помощью memmove и скорректировать адрес массива.
j123123 15.05.2019 20:38 # +1
nemyx 15.05.2019 21:01 # 0
С контекстом была другая фигня, которую отменили: «Специальное свойство __caller__, возвращающее объект активации вызывающей функции и, таким образом, позволяющее восстанавливать стек вызовов, было удалено по соображениям безопасности».
guest8 15.05.2019 21:13 # −999
guest8 15.05.2019 22:33 # −999
guest12 15.05.2019 23:00 # −100
guest8 15.05.2019 19:24 # −999
Increment_Excrement 20.05.2019 01:41 # 0
gost 20.05.2019 02:05 # 0
cmepmop 20.05.2019 10:49 # 0
guest8 21.05.2019 03:58 # −999
cmepmop 21.05.2019 23:30 # 0
Я без тебе всi дни y полонi печалi.
guest8 22.05.2019 02:32 # −999
Increment_Excrement 22.05.2019 00:57 # 0
А на ppc вместо дедика софтварная stack machine.
Ой...
guest8 22.05.2019 02:31 # +1
Orange_Ikarus 22.05.2019 03:24 # 0
npocmou_xyu 02.08.2019 01:25 # −1
Где сишкопосты, обсёры крестов, а главное ГОМОИКОНЫ?
guest8 02.08.2019 01:45 # +1
kcalbCube 04.04.2022 23:51 # 0
kcalbCube 07.04.2022 15:52 # 0
kcalbCube 07.04.2022 17:16 # 0