assembly low-level masm32

assembly - Ensamblaje-.data,.code y registros...?



low-level masm32 (2)

¡Intentemos responder en orden!

  1. La sección de datos contiene todo lo que desea que el sistema inicialice automáticamente antes de que llame al punto de entrada de su programa. Tienes razón, normalmente las variables globales terminan aquí. Los datos inicializados a cero generalmente no se incluyen en el archivo ejecutable, ya que no hay ninguna razón para hacerlo: un par de directivas para el cargador de programas son todo lo que se necesita para generar ese espacio. Una vez que su programa comienza a ejecutarse, las regiones ZI y de datos son generalmente intercambiables. Wikipedia tiene mucha más información.

  2. Las variables no existen realmente cuando se ensambla la programación, al menos no en el sentido en que lo hacen cuando se escribe código C. Todo lo que tienes son las decisiones que has tomado sobre cómo diseñar tu memoria. Las variables pueden estar en la pila, en algún lugar de la memoria, o simplemente vivir solo en registros.

  3. Los registros son el almacenamiento de datos interno del procesador. En general, solo puede realizar operaciones en valores en los registros del procesador. Puede cargar y almacenar sus contenidos en y desde la memoria, que es la operación básica de cómo funciona su computadora. Aquí hay un ejemplo rápido. Este código C:

    int a = 5; int b = 6; int *d = (int *)0x12345678; // assume 0x12345678 is a valid memory pointer *d = a + b;

    Podría traducirse a un ensamblaje (simplificado) a lo largo de las líneas de:

    load r1, 5 load r2, 6 load r4, 0x1234568 add r3, r1, r2 store r4, r3

    En este caso, puede pensar en los registros como variables, pero en general no es necesario que una variable permanezca siempre en el mismo registro; dependiendo de qué tan complicada sea su rutina, puede que ni siquiera sea posible. Deberá insertar algunos datos en la pila, desconectar otros datos, y así sucesivamente. Una ''variable'' es esa pieza lógica de datos, no donde vive en memoria o registros, etc.

  4. Una matriz es solo un bloque contiguo de memoria: para una matriz local, puede disminuir el puntero de la pila de forma adecuada. Para una matriz global, puede declarar ese bloque en la sección de datos.

  5. Hay un montón de convenciones sobre registros: consulte el ABI de su plataforma o llame al documento de la convención para obtener detalles sobre cómo usarlos correctamente. La documentación de su ensamblador también puede tener información. Consulte el artículo de ABI en wikipedia .

  6. Su programa ensamblador puede hacer las mismas llamadas al sistema que cualquier programa C, así que puede llamar a malloc() para obtener memoria del montón.

Así que esta mañana publiqué una pregunta confusa sobre el montaje y recibí una gran ayuda genuina, que realmente aprecio.

Y ahora estoy empezando a ensamblar y estoy empezando a entender cómo funciona.

Las cosas que creo que entiendo bien incluyen la pila, las interrupciones, el binario / hex, y en general lo que hacen la mayoría de las operaciones básicas (jmp, push, mov, etc.).

Los conceptos que estoy luchando por comprender y con los que me gustaría obtener ayuda están a continuación. Sería de gran ayuda si pudiera abordar alguno de los siguientes aspectos:

  1. ¿Qué está pasando exactamente en la sección .data? ¿Son esas variables las que estamos declarando?
  2. Si es así, ¿podemos declarar variables más adelante en la sección del código? ¿Si no, porque no? Si es así, ¿cómo y por qué usamos la sección de datos?
  3. ¿Qué es un registro? ¿Cómo se compara con una variable? Quiero decir que sé que es un lugar que almacena una pequeña información ... pero eso suena exactamente como una variable para mí.
  4. ¿Cómo hago una matriz? Sé que parece algo aleatorio, pero tengo curiosidad sobre cómo haré algo como esto.
  5. ¿Existe alguna lista de prácticas comunes para cada registro? Todavía no los entiendo completamente, pero he notado que algunas personas dicen, por ejemplo, que se debe usar un cierto registro para almacenar los "valores de retorno" de los procedimientos. ¿Existe una lista exhaustiva o al menos informativa de tales prácticas?
  6. Una de las razones por las que estoy aprendiendo asamblea es para comprender mejor lo que está sucediendo detrás de mi código de alto nivel. Con eso en mente, cuando estoy programando en c ++, a menudo pienso en la pila y el montón. En el montaje, sé lo que es la pila: ¿dónde está el "montón"?

Algo de información: estoy usando masm32 con WinAsm como un IDE, y estoy trabajando en Windows 7. Tengo mucha experiencia previa en programación en lenguajes de nivel superior como c ++ / java.

editar: Gracias por ayudar a todos, ¡extremadamente informativo como de costumbre! ¡Buena cosa! Sin embargo, una última cosa: me pregunto cuál es la diferencia entre el Stack Pointer y el puntero Base, o ESP y EBP. ¿Alguien me puede ayudar?

editar: Creo que ahora lo entiendo ... ESP siempre apunta a la cima de la pila. Sin embargo, puede señalar a EBP en lo que quiera. ESP se maneja automáticamente, pero puede hacer lo que quiera con EBP. Por ejemplo:

push 6 push 5 push 4 mov EBP, ESP push 3 push 2

En este escenario, EBP ahora apunta a la dirección que contiene 4, pero ESP ahora apunta a la dirección que contiene 2.

En una aplicación real, 6, 5 y 4 podrían haber sido argumentos de función, mientras que 3 y 2 podrían ser variables locales dentro de esa función.


Me gustaría agregar a esto. Los programas en una computadora generalmente se dividen en tres secciones, aunque hay otros.

Segmento de código - .code, .text: http://en.wikipedia.org/wiki/Code_segment

En informática, un segmento de código, también conocido como segmento de texto o simplemente como texto, es una frase utilizada para referirse a una parte de la memoria o de un archivo objeto que contiene instrucciones ejecutables. Tiene un tamaño fijo y generalmente es de solo lectura. Si la sección de texto no es de solo lectura, entonces la arquitectura particular permite el código de auto modificación. El código de solo lectura es reentrante si puede ser ejecutado por más de un proceso al mismo tiempo. Como región de memoria, un segmento de código reside en las partes inferiores de la memoria o en su parte inferior, para evitar que el montón y los desbordamientos de la pila lo sobrescriban.

Segmento de datos - .data: Wikipedia

Un segmento de datos es una de las secciones de un programa en un archivo de objeto o en memoria, que contiene las variables globales y las variables estáticas que el programador inicializa. Tiene un tamaño fijo, ya que el programador establece todos los datos en esta sección antes de cargar el programa. Sin embargo, no es de solo lectura, ya que los valores de las variables pueden modificarse en tiempo de ejecución. Esto está en contraste con la sección Rodata (datos constantes de solo lectura), así como con el segmento de código (también conocido como segmento de texto).

BSS: http://en.wikipedia.org/wiki/.bss

En la programación de computadoras, muchos compiladores y enlazadores utilizan sbs o bss (que originalmente significaba Bloque iniciado por símbolo) como el nombre de una parte del segmento de datos que contiene variables estáticas y variables globales que se rellenan únicamente con datos de valor cero inicialmente (es decir, cuando comienza la ejecución). A menudo se conoce como la "sección bss" o "segmento bss". El cargador de programas inicializa la memoria asignada para la sección bss cuando carga el programa.

Los registros son, según lo descrito por otros, instalaciones de la CPU para almacenar datos o una dirección de memoria. Las operaciones se realizan en registros, como add eax, ebx y dependiendo del dialecto de ensamblaje, eso significa cosas diferentes. En este caso, esto se traduce para agregar los contenidos de ebx a eax y almacenarlos en eax (sintaxis de NASM). El equivalente en GNU AS (AT & T) es: movl $ebx, $eax . Los diferentes dialectos de ensamblaje tienen diferentes reglas y operadores. No soy fanático de MASM por esta razón, es muy diferente a NASM, YASM y GNU AS.

En realidad, no hay una interacción general con C. ABI que designe cómo sucede esto; por ejemplo, en x86 (Unix) encontrará los argumentos de un método en la pila, mientras que en x86-64 en Unix, los primeros argumentos se colocarán en registros. Ambos ABI esperan que el resultado de la función se almacene en el registro eax / rax.

Aquí hay una rutina de agregar de 32 bits que se ensambla tanto para Windows como para Linux.

_Add push ebp ; create stack frame mov ebp, esp mov eax, [ebp+8] ; grab the first argument mov ecx, [ebp+12] ; grab the second argument add eax, ecx ; sum the arguments pop ebp ; restore the base pointer ret

Aquí, puedes ver a qué me refiero. El valor de "retorno" se encuentra en eax. Por el contrario, la versión x64 se vería así:

_Add push rbp ; create stack frame mov rbp, rsp mov eax, edi ; grab the first argument mov ecx, esi ; grab the second argument add eax, ecx ; sum the arguments pop rbp ; restore the base pointer ret

Hay documentos que definen este tipo de cosas. Aquí está el UNIX x64 ABI: http://www.x86-64.org/documentation/abi-0.99.pdf . Estoy seguro de que probablemente puedas encontrar ABI para cualquier procesador, plataforma, etc. que necesites.

¿Cómo se opera en una matriz en el ensamblaje? Aritmética del puntero. Dada una dirección base en eax el siguiente entero almacenado estaría en [eax+4] si el entero tiene 4 bytes de tamaño. Puede crear este espacio usando llamadas hasta malloc / calloc, o puede llamar a la llamada del sistema de asignación de memoria, sea lo que sea que esté en su sistema.

¿Cuál es el ''montón''? De acuerdo con la wikipedia nuevamente, es el área de memoria reservada para la asignación de memoria dinámica. No lo verá en su programa de ensamblaje hasta que llame a calloc, malloc o la llamada al sistema de asignación de memoria, pero está allí.

Perdón por el ensayo.