Если Вы имеете контроль над xml поколением на первом вхождении страны, Вы могли бы добавить, что атрибут к узлу страны, такому как отличный ='true' отмечает страну, как "используется" и не впоследствии добавляет отличный атрибут при случайной встрече с той страной снова.
Вы могли тогда сделать
<xsl:for-each select="Artists_by_Countries/Artist_by_Country/Country[@distinct='true']" />
Как уже указывалось, 0xBF ... являются указателями кадров и 0x08 ... адресами возврата.
Заполнение связано с проблемами выравнивания . Другие нераспознанные значения также заполняются, поскольку стек не инициализируется до нуля или любого другого значения. Неинициализированные переменные и неиспользуемое пространство заполнения будут содержать все байты, находящиеся в этих ячейках памяти.
Такая проверка стека кажется слишком далекой. Я мог бы предложить загрузить вашу программу в отладчике, переключиться на представление на языке ассемблера и выполнить пошаговое выполнение каждой машинной инструкции. Понимание стека ЦП обязательно требует понимания машинных инструкций, работающих с ним, и это будет более прямой способ увидеть, что происходит.
Как уже упоминалось, структура стека также сильно зависит от процессора. архитектура, с которой вы работаете.
Скорее всего, это канарейки . Ваш компилятор добавляет код для отправки дополнительных данных в стек и последующего чтения их обратно для обнаружения переполнения стека.
Я предполагаю, что значения, начинающиеся с 0x0804, являются адресами в сегменте кода вашей программы (например, адреса возврата для вызовов функций). Те, которые начинаются с 0xBF814 и которые вы пометили как адреса возврата, являются адресами в стеке - данными, а не кодом. Я предполагаю, что это, вероятно, указатели кадров.
Адреса 0xBF ... будут ссылками на предыдущий фрейм стека:
0xBF8144D8 : BF8144F8 //return address for trace
0xBF8144DC : 0804845A //
0xBF8144F8 : BF814518 //return address for func3
0xBF8144FC : 08048431 //????
0xBF814518 : BF814538 //return address for func2?
0xBF81451C : 0804840F //????
0xBF814538 : BF814558 //return address for func1
0xBF81453C : 080483E8 //????
Адреса 0x08 ... будут адресами кода, к которому нужно вернуться в каждом случае.
Я не могу говорить о других вещах в стеке; вам нужно будет пройти через ассемблер и посмотреть, что именно он делает. Я предполагаю, что он выравнивает начало каждого кадра с определенным выравниванием, так что __ attribute __ ((align))
(или как там он сейчас называется ...) работает.
Компилятор использует EBP для хранения базового адреса кадра. Прошло некоторое время, поэтому я посмотрел на это, поэтому могу немного ошибиться в деталях, но идея такая.
У вас есть три шага при вызове функции:
call
, которая помещает адрес возврата в стек и переходит к новой функции. PUSHAD
) push EBP
mov EBP, ESP
Когда функция возвращает его:
ret
инструкция, которая выскакивает из адреса возврата и переходит туда. pop EBP
ret
Вопрос в том, почему передается EBP и почему в него копируется ESP?
Когда вы вводите функцию, ESP указывает на самую низкую точку в стеке для этой функции. Любые переменные, которые вы объявляете в стеке, доступны как [ESP + offset_to_variable]
. Это просто! Но учтите, что ESP должен всегда указывать на вершину стека, поэтому, когда вы объявляете новую переменную в стеке, ESP изменяется. Теперь [ESP + offset_to_variable]
не так уж и хорош, потому что вы должны помнить, какой ESP был в то время, когда переменная была выделена.
Вместо этого в первую очередь функция должна сделать - скопировать ESP в EBP. EBP не изменится в течение жизни функции, поэтому вы можете получить доступ ко всем переменным, используя `[EBP + offset_to_variable]. Но теперь у вас есть другая проблема, потому что, если вызываемые функции вызывают другую функцию, EBP будет перезаписан. Вот почему перед копированием EBP его необходимо сохранить в стеке, чтобы его можно было восстановить перед возвратом к вызывающей функции.
потому что вы должны помнить, каким был ESP в момент выделения переменной.Вместо этого первое, что нужно сделать функции, - это скопировать ESP в EBP. EBP не изменится в течение жизни функции, поэтому вы можете получить доступ ко всем переменным, используя `[EBP + offset_to_variable]. Но теперь у вас есть другая проблема, потому что, если вызываемые функции вызывают другую функцию, EBP будет перезаписан. Вот почему перед копированием EBP его необходимо сохранить в стеке, чтобы его можно было восстановить до возврата к вызывающей функции.
потому что вы должны помнить, каким был ESP в момент выделения переменной.Вместо этого первое, что нужно сделать функции, - это скопировать ESP в EBP. EBP не изменится в течение жизни функции, поэтому вы можете получить доступ ко всем переменным, используя `[EBP + offset_to_variable]. Но теперь у вас есть другая проблема, потому что, если вызываемые функции вызывают другую функцию, EBP будет перезаписан. Вот почему перед копированием EBP его необходимо сохранить в стеке, чтобы его можно было восстановить до возврата к вызывающей функции.
Но теперь у вас есть другая проблема, потому что, если вызываемые функции вызывают другую функцию, EBP будет перезаписан. Вот почему перед копированием EBP его необходимо сохранить в стеке, чтобы его можно было восстановить до возврата к вызывающей функции. Но теперь у вас есть другая проблема, потому что, если вызываемые функции вызывают другую функцию, EBP будет перезаписан. Вот почему перед копированием EBP его необходимо сохранить в стеке, чтобы его можно было восстановить перед возвратом к вызывающей функции.Это отладочная или окончательная сборка? Я бы ожидал некоторого дополнения к отладочным сборкам для обнаружения переполнения стека.