Nano Hash - криптовалюты, майнинг, программирование

Отличие локальных переменных в основной и другой функции

Я запутался. Я объявляю переменную в функции main и другую переменную в другой функции. Но в gdb я обнаружил, что программа посещает переменную в функции main по регистру %esp и посещает переменную в другой функции по регистру %ebp. разве все это не должно посещаться функцией %ebp? Или это скрытое правило, что посещение %esp регистрируется в main, которого я не знаю?

/* source_file.c */
#include <stdio.h>

void localfunc(void)
{
    int local_in_func;
    local_in_func = 0x21;
    printf("local_in_func = %d\n", local_in_func);
}
int main(int argc, char **argv)
{
    int local_in_main;
    local_in_main = 0x97;
    printf("local_in_main = %d\n", local_in_main);
    return 0;
}

И его код дизассемблирования ниже:

(gdb) disassemble main
Dump of assembler code for function main:
   0x08048407 <+0>: push   %ebp
   0x08048408 <+1>: mov    %esp,%ebp
   0x0804840a <+3>: and    $0xfffffff0,%esp    ; visit local_in_main by esp
   0x0804840d <+6>: sub    $0x20,%esp
   0x08048410 <+9>: movl   $0x97,0x1c(%esp)
   0x08048418 <+17>:    mov    $0x8048524,%eax
   0x0804841d <+22>:    mov    0x1c(%esp),%edx
   0x08048421 <+26>:    mov    %edx,0x4(%esp)
   0x08048425 <+30>:    mov    %eax,(%esp)
   0x08048428 <+33>:    call   0x8048300 <printf@plt>
   0x0804842d <+38>:    mov    $0x0,%eax
   0x08048432 <+43>:    leave  
   0x08048433 <+44>:    ret    
End of assembler dump.

(gdb) disassemble localfunc
Dump of assembler code for function localfunc:
   0x080483e4 <+0>: push   %ebp
   0x080483e5 <+1>: mov    %esp,%ebp
   0x080483e7 <+3>: sub    $0x28,%esp
   0x080483ea <+6>: movl   $0x21,-0xc(%ebp)    ; visit local_in_func by ebp
   0x080483f1 <+13>:    mov    $0x8048510,%eax
   0x080483f6 <+18>:    mov    -0xc(%ebp),%edx
   0x080483f9 <+21>:    mov    %edx,0x4(%esp)
   0x080483fd <+25>:    mov    %eax,(%esp)
   0x08048400 <+28>:    call   0x8048300 <printf@plt>
   0x08048405 <+33>:    leave  
   0x08048406 <+34>:    ret    
End of assembler dump.

Мои инструменты:

  • ОС: убунту 12.04

  • скомпилировать: gcc версии 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)

  • отладка: GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04


  • код для main() также имеет дополнительный and $0xfffffff0,%esp, почему это? 23.12.2014
  • Попробуйте с -O. Ваши функции не эквивалентны, поскольку они что-то возвращают. Предположения, которые gcc может сделать о выравнивании стека, могут отличаться для main. 23.12.2014
  • и $0xfffffff0,%esp выравнивает стек. 23.12.2014
  • Я пробую с -O и меняю main на void main(void), это эквивалентно другой функции. И результат, который я получаю, заключается в том, что в обеих функциях программа посещает локальную переменную по регистру %esp. 24.12.2014

Ответы:


1

Обычно %esp — это указатель стека, а %ebp — это «базовый» указатель, который обычно устанавливается в том месте, где указатель стека находился в начале функции.

Функции создают локальные переменные, помещая их в стек либо с помощью прямого push, либо путем логического эквивалента вычитания смещения из %esp и обращения к пробелу между старым %esp (то есть %ebp) и новым %esp.

Это можно сделать либо с положительным смещением от %esp (например, через 0x1c(%esp) в main), либо с отрицательным смещением от %ebp (например, -0xc(%ebp) в `local_function1). Логической разницы нет, хотя у компиляторов есть много эвристик производительности для выбора между несколькими способами достижения одной и той же цели.

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

23.12.2014
  • А на x86 некоторым функциям даже не нужно перемещать sp из-за красной зоны (дело в том, что компилятору не нужно подчиняться правилам учебника). 23.12.2014
  • Привет, спасибо за ваш ответ. Я понимаю в основном ваш ответ, но я ничего не знаю о красной зоне, я поищу ее позже. И моя проблема в том, что я меняю %esp в основной функции встроенным кодом asm, и это приведет к тому, что я потерял свои локальные переменные в функции main. Итак, как я могу решить эту проблему? Большое спасибо! 24.12.2014
  • Есть разные способы сделать это. Одним из них является использование расширенного синтаксиса встроенного ассемблера, который позволяет вам использовать переменные в ассемблере... См. здесь: gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html. 24.12.2014
  • Извините, я не ясно выразился. Я имею в виду, что я объявляю локальную переменную в main функции с помощью C кода, затем я изменяю %esp регистр с помощью встроенного asm кода, а затем я пытаюсь использовать C код для посещения объявленной мной локальной переменной, но программа посещает локальную переменную с помощью %esp, поэтому, прежде чем я изменю, например, переменная находится в -0xc(%esp), но теперь 0xc(%esp) не является местоположением переменной, потому что я изменил %esp. Я не являюсь носителем английского языка, возможно, мое описание неясно, извините за это. Спасибо за ваш ответ искренне. 24.12.2014
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..