LI Unidad01 Diapositivas

Descargar como pptx, pdf o txt
Descargar como pptx, pdf o txt
Está en la página 1de 47

Instituto Tecnológico de Culiacán

Ing. en Sistemas Computacionales


Lenguajes de Interfaz

Unidad I: Introducción al Lenguaje Ensamblador


Introducción al Lenguaje
Ensamblador
 Importancia de la programación en lenguaje
ensamblador.
 El procesador y sus registros internos
 La memoria principal (RAM)
 El concepto de interrupciones
 Llamadas a servicios del sistema
 Modos de direccionamiento
 Proceso de ensamblado y ligado
 Desplegado de mensajes en el monitor
Introducción al Lenguaje
Ensamblador

 Importancia de la programación en lenguaje


ensamblador.
Importancia de la Programación en
Lenguaje Ensamblador
Lenguaje ensamblador es un lenguaje de programación de
computadoras, considerado de bajo nivel, y constituye la
representación más directa del código máquina específico para
cada arquitectura de computadoras, que es legible para un
programador.

Fue usado principalmente en los inicios del desarrollo de


software, cuando aun no se contaba con los potentes lenguajes
de alto nivel. Actualmente se utiliza con frecuencia en ambientes
académicos y de investigación, especialmente cuando se
requiere la manipulación directa de hardware, se pretenden altos
rendimientos o un uso de recursos controlado y reducido.
Características
El código escrito en lenguaje ensamblador posee una cierta
dificultad de ser entendido directamente por un ser humano ya
que su estructura se acerca mas bien al lenguaje máquina, es
decir, lenguaje de bajo nivel.

El lenguaje ensamblador es difícilmente portable, es decir, un


código escrito para un microprocesador en particular necesita
ser modificado muchas veces en su totalidad para poder ser
usado en otro microprocesador.
Características
Los programas hechos en lenguaje ensamblador son
generalmente más rápidos y consumen menos recursos del
sistema (memoria RAM y ROM). Al programar cuidadosamente
en lenguaje ensamblador se pueden crear programas que se
ejecutan más rápidamente y ocupan menos espacio que con
lenguajes de alto nivel.

Con el lenguaje ensamblador se tiene un control muy preciso de


las tareas realizadas por un microprocesador por lo que se
pueden crear segmentos de código difíciles de programar en un
lenguaje de alto nivel.
Ensamblador
Un ensamblador (assembler en inglés) es un programa que crea
código objeto traduciendo instrucciones nemónicas de un
programa fuente escrito en lenguaje ensamblador a códigos
ejecutables e interpretando los nombres simbólicos para
direcciones de memoria y otras entidades (ensamblado).

El uso de referencias simbólicas es una característica básica del


lenguaje ensamblador, evitando tediosos cálculos y
direccionamiento manual después de cada modificación del
programa. La mayoría de los ensambladores también incluyen
facilidades para crear macros, a fin de generar series de
instrucciones cortas que se ejecutan en tiempo real, en lugar de
utilizar subrutinas.
Usos y Aplicaciones
La mayoría de las aplicaciones que se ejecutan en una
computadora han sido desarrolladas empleando algún lenguaje
de alto nivel, de los cuales hay infinidad, tales como: C, C++,
Pascal, COBOL, Java, PHP, C#, Visual Basic, Perl, Python y un
largo etcétera más.

En una gran parte de estos desarrollos la elección de un


lenguaje u otro es casi una preferencia personal, puesto que en
general comparten una funcionalidad, e incluso una sintaxis,
muy similar.
Usos y Aplicaciones
En contraposición, el lenguaje ensamblador se dirige a tipos de
proyectos y situaciones muchos más concretos y específicos. En
muchos casos este lenguaje se utiliza no para desarrollar una
aplicación completa, sino para mejorar la velocidad de ciertas
partes de un programa o bien realizar operaciones que, desde el
lenguaje de alto nivel, no estén accesibles de otra forma.

En dispositivos con poca capacidad de memoria y potencia


limitada, como los antes mencionados, sí que suele recurrirse al
ensamblador como recurso principal para definir su
programación.
Usos y Aplicaciones
Asimismo la programación en lenguaje ensamblador es un
recurso, un medio más que un fin, utilizado en la mayoría de las
carreras relacionadas con la informática para acercar al
estudiante a las interioridades de los microprocesadores,
facilitándole el conocimiento de su arquitectura así como su
funcionamiento.

En este sentido la escritura de programas en ensamblador


fortalece el pensamiento analítico del programador, ya que se ve
forzado a dividir el problema a resolver en una multitud de
operaciones más sencillas, repitiendo el proceso hasta poder
expresar esas operaciones mediante los códigos de operación
con que cuente el microprocesador.
Usos y Aplicaciones
En cualquier caso, el aprendizaje de un lenguaje como el
ensamblador, tanto si en el futuro se utiliza allí donde resulte
adecuado como si no, es un proceso que le aportará una gran
cantidad de conocimientos útiles que van desde saber cómo se
almacenan ciertos tipos de datos en la memoria hasta aprender
a utilizar los servicios de la BIOS que incorpora toda
computadora.
Introducción al Lenguaje
Ensamblador

 El procesador y sus registros internos


El microprocesador
El microprocesador está, conceptualmente, formado por tres
partes:

 Unidad de control

 Unidad aritmética lógica (ALU)

 Registros
Sistema de control de la unidad de
ejecución
Es el encargado de decodificar las instrucciones que le envía la
cola y enviarle las órdenes a la unidad aritmética y lógica según
una tabla que tiene almacenada en ROM llamada CROM (Control
Read Only Memory).
Unidad Aritmética Lógica
Es la encargada de realizar las operaciones aritméticas (suma,
suma con "arrastre", resta, resta con "préstamo" y
comparaciones) y lógicas (AND, OR, XOR y TEST). Las
operaciones pueden ser de 32 bits, 16 bits o de 8 bits.
Registros del 80x86
Los registros de un microprocesador son componentes dentro
del microprocesador que nos permiten almacenar datos. Estos
datos pueden representar valores sobre los cuales se van a
realizar operaciones, resultados de las operaciones, direcciones
de localidades de memoria donde se encuentran datos e
instrucciones, direcciones de los dispositivos de entrada/salida
sobre los que deseamos escribir o leer, o los datos a escribir o
leídos de esos dispositivos.

El número, tamaño y uso de los registros de un microprocesador


así como su conjunto de instrucciones determina la eficiencia con
que el microprocesador realiza una tarea. A la descripción del
número, tamaño y uso de los registros de un microprocesador se
le conoce como el modelo de programación del microprocesador.
Registros del 80x86
Registros de propósito general
Los registros de propósito general, como su nombre lo indica, se
utilizan en la forma en que lo desee el programador. Cada uno de
estos registros se puede direccionar como un registro de 32 bits
(EAX, EBX, ECX, EDX), de 16 bits (AX, BX, CX, DX) o como un registro
de 8 bits (AH, AL, BH, BL, CH, CL, DH, DL). Cada uno de los registros
de 16 bits está formado por la concatenación de dos registros de 8
bits: AX = AH:AL, BX = BH:BL, CX = CH:CL y DX = DH:DL, donde el
bit 0 del registro AH es el bit 8 del registro AX, etc.

Adicionalmente, algunas de las instrucciones del microprocesador


emplean los registros de propósito general para tareas específicas.
Por esta razón, a cada uno se le da su nombre (Acumulador, Base,
Contador y Datos). Las funciones primarias de los registros de
propósito general incluyen:
Registros de propósito general
EAX, AX, AH, AL (Acumulador): Se utiliza como registro principal
para la realización de operaciones aritméticas o lógicas.

EBX, BX, BH, BL (Base): Se utiliza para guardar la dirección base de


listas de datos en la memoria.

ECX, CX, CH, CL (Contador): Contiene el conteo para ciertas


instrucciones de corrimientos y rotaciones, de iteraciones en el
ciclo LOOP y operaciones repetidas de cadenas.

EDX, DX, DH, DL (Datos): Se utiliza como registro de datos en las


operaciones de entrada/salida de datos, además contiene la parte
más significativa de un producto después de una multiplicación;
la parte más significativa del dividendo antes de la división.
Registros apuntadores e índices
ESP (Apuntador de pila): Contiene la dirección de memoria del
tope de la pila del programa.

EBP (Apuntador de base): Contiene una dirección de memoria de


la pila de un programa.

ESI (Índice fuente): Contiene una dirección de memoria de un


elemento de un arreglo o cadena.

EDI (Índice destino): Contiene una dirección de memoria de un


elemento de una cadena o arreglo.
Registros de segmento
Los registros de segmentos contiene la dirección de memoria
donde se encuentran los selectores de segmento, que
especifican la dirección de inicio del segmento y la longitud del
mismo. El código y los datos de un programa en ejecución se
encuentran cada uno en uno o más segmentos de memoria. La
pila del programa ocupa otro segmento. Los registros de
segmento son:
Registros de segmento
CS (Código): Tiene la dirección del descriptor de segmento que indica
donde se encuentra el código de un programa..

DS (Datos): Tiene la dirección del descriptor de segmento en que se


encuentran los datos estáticos de un programa.

ES (Extra): Este registro también tiene la dirección de un descriptor de


segmento en que se encuentran los datos estáticos de un programa.

SS (Pila): Tiene la dirección lógica del descriptor de segmento en que se


encuentran la pila del sistema.

FS y GS: Son registros de segmento suplementarios disponibles en los


procesadores 80386 y superiores para permitir que los programas
accedan a dos segmentos de memoria adicional
Registros varios
EIP (Apuntador de instrucciones): Contiene la dirección de
memoria que contiene la siguiente instrucción que va a
ejecutar el microprocesador.

EFLAGS (Banderas): Cada bandera es un bit en el registro de


banderas, también llamado registro de código de condiciones.
En la siguiente figurase ilustra el registro de banderas.
Aunque el registro de banderas es de 32 bits sólo hay
dieciocho banderas. Los otros 14 bits no son usados.
Banderas de estado
C (Acarreo): Indica un acarreo después de una suma o un
préstamo después de una resta. La bandera de acarreo también
indica condiciones de error en ciertos programas y
procedimientos.

P (Paridad): Es un cero para una paridad impar y un 1 para una


paridad par. La paridad es un conteo de unos expresada como un
número par e impar.

A (Acarreo auxiliar): Indica un acarreo después de una suma o un


préstamo después de una resta del bit 3 al bit 4 en el resultado.
Esta bandera sólo se utiliza en las operaciones DAA y DAS para
ajustar el valor de AL después de una suma o resta BCD.
Banderas de estado
Z (Cero): Indica que el resultado de una operación aritmética o lógica es
cero. Si Z = 1, el resultado es cero y si Z = 0, el resultado no es cero.

S (Signo): Indica el signo aritmético del resultado después de una suma


o una resta. Si S = 1, el resultado es negativo. Si S = 0, el resultado es
positivo. Se debe tener en cuenta que el valor del bit más significativo
aparece en el bit de signo en cualquier instrucción que afecte las
banderas.

O (Sobreflujo): Es una condición que ocurre cuando se suman o se


restan números con signo. Un sobreflujo indica que el resultado ha
excedido la capacidad de la máquina. Por ejemplo si se suma 7FH +
01H (127 + 1) el resultado es 80H (-128). Este resultado representa una
situación de sobreflujo señalado por la bandera para la suma con signo.
Para operaciones sin signo esta bandera se ignora.
Banderas de control
T (Trampa): Activa, si se pone a 1, o desactiva, si se pone a 0, el modo
de ejecución paso a paso. Este modo es utilizado por los depuradores
para ejecutar las instrucciones una a la vez y permitir observar el efecto
de la instrucción sobre los registros y la memoria.

I (Interrupción): Habilita, si se pone a 1, o deshabilita, si se pone a 0, las


interrupciones al microprocesador. El estado de esta bandera se
controla con las instrucciones STI (habilitar interrupciones) y CLI
(desactivar las interrupciones).

D (Dirección): Controla la selección de autoincremento o


autodecremento de los registros DI o SI durante las instrucciones de
cadenas y arreglos. Si D = 1 hay autodecremento en los registros y si D
= 0 hay autoincremento. El estado de esta bandera se controla con las
instrucciones STD (habilitar dirección) y CLD (desactivar dirección).
Banderas de control
IOPL (Nivel de privilegio de E/S): Es utilizado en las operaciones en
modo protegido para seleccionar el nivel de privilegio de los
dispositivos de E/S.

NT (Tarea anidada): Indica que la tarea actual está anidada dentro de


otra tarea en el modo de operación protegido. Esta bandera se pone a 1
cuando la tarea es anidada por software.

RF (Resumen): Es usada con el depurador para controlar la continuación


de la ejecución después de la siguiente instrucción.
Banderas de control
VM (Modo virtual): Selecciona el modo virtual de operación en un
sistema en modo protegido.

AC (Verificación de alineación): Se activa si una palabra o doble palabra


están direccionados en una posición que no es palabra o doble palabra.
Solo utilizado por el procesador 86486SX.

ID (Identificación): Indica que los procesadores Pentium – Pentium 4


reconocen la instrucción CPUID.
Banderas de control
VIF (Interrupción virtual): Es una copia de la bandera de interrupción
disponible a los microprocesadores Pentium – Pentium 4.

VIP (Interrupción virtual pendiente): Proporciona información acerca de


la interrupción en modo virtual para los procesadores Pentium –
Pentium 4.
Introducción al Lenguaje
Ensamblador

 La memoria principal (RAM)


Memoria Principal
La memoria es un conjunto o arreglo de celdas binarias de
longitud definida (8, 16, 32 o 64 bits), en las cuales se puede
almacenar instrucciones codificadas y datos.

Cada uno de estos celdas se caracteriza por tener una dirección


única, por lo que generalmente cada una de estas localidades se
identifica por su dirección la cual es la posición que le toca a esa
celda dentro del arreglo.

Las direcciones se expresan siempre en hexadecimal.


Modos de operación
 Los procesadores actuales tienen diferentes modos de operación. He aquí las
descripciones breves de cada modo:

◦ Modo protegido El modo protegido es el estado nativo del procesador, en el que están
disponibles todas las instrucciones y características. Los programas reciben áreas separadas de
memoria llamadas segmentos, y el procesador evita que los programas hagan referencia a la
memoria que se encuentra fuera de sus segmentos asignados.

◦ Modo 8086 virtual Mientras se encuentra en modo protegido, el procesador puede ejecutar en
forma directa el software para modo de direccionamiento real, como los programas de MS-DOS,
en un entorno multitarea seguro. En otras palabras, si un programa de MS-DOS falla o trata de
escribir datos en el área de memoria del sistema, no afectará a los otros programas que se
ejecuten al mismo tiempo. Windows XP puede ejecutar varias sesiones separadas en modo 8086
a la vez.

◦ Modo de direccionamiento real Este modo implementa el entorno de programación del


procesador 8086 de Intel, con unas cuantas características adicionales, como la habilidad de
cambiar a otros modos. Este modo está disponible en Windows 98 y puede usarse para ejecutar
un programa de MS-DOS que requiera el acceso directo a la memoria del sistema y a los
dispositivos de hardware. Los programas que se ejecutan en modo de direccionamiento real
pueden hacer que el sistema operativo falle (que deje de responder a los comandos).
Administración de memoria
 Los procesadores nuevos administran la memoria de acuerdo a los modos
básicos de operación vistos anteriormente. El modo protegido es el más
simple y poderoso; los demás se utilizan, por lo general, cuando los
programas deben acceder directamente al hardware del sistema.

 En el modo de direccionamiento real sólo puede direccionarse 1MB de


memoria, del 00000 al FFFFF hexadecimal.

 El procesador sólo puede ejecutar un programa a la vez, pero puede


interrumpir en forma momentánea ese programa para procesar las solicitudes
(conocidas como interrupciones) de los periféricos.

 Los programas de aplicación pueden leer y modificar cualquier área de la


RAM (memoria de acceso aleatorio) y pueden leer pero no modificar cualquier
área de la ROM (memoria de sólo lectura). El sistema operativo MS-DOS se
ejecuta en modo de direccionamiento real, y Windows 95/98 puede cargarse
en este modo.
Administración de memoria
 En el modo protegido, el procesador puede ejecutar varios programas al
mismo tiempo. A cada proceso (programa en ejecución) le asigna un total de
4GB de memoria. A cada programa se le puede asignar su propia área
reservada de memoria, y los programas no pueden acceder de manera
accidental al código y los datos de los demás programas. Windows y Linux se
ejecutan en modo protegido.

 En el modo 8086 virtual, la computadora se ejecuta en modo protegido y crea


una máquina 8086 virtual con su propio espacio de direcciones de 1MB, que
simula a una computadora 80×86 que se ejecuta en modo de
direccionamiento real.

 Por ejemplo, Windows NT y 2000 crean una máquina 8086 virtual cuando
abrimos una ventana de Comandos. Puede ejecutar muchas de esas ventanas
al mismo tiempo, y cada una está protegida contra las acciones de las demás.
Algunos programas de MS-DOS que hacen referencias directas al hardware de
la computadora no se ejecutarán en este modo bajo Windows NT, 2000 y XP
Modo protegido
 El modo protegido es el modo “nativo” más poderoso del procesador. Al ejecutarse en
modo protegido, un programa puede acceder a 4GB de memoria, con direcciones desde
0 hasta FFFFFFFF hexadecimal.

 En el contexto de Microsoft Assembler, el modelo de memoria plano (flat) es apropiado


para la programación en modo protegido. El modelo plano es fácil de usar, ya que sólo
requiere un entero de 32bits para guardar la dirección de una instrucción o variable.

 La CPU realiza el cálculo y la traducción de las direcciones en segundo plano, todo lo


cual es transparente para los programadores de aplicaciones. Los registros de segmento
(CS, DS, SS, ES, FS, GS) apuntan a tablas de descriptores de segmentos , que el sistema
operativo utiliza para llevar el registro de las ubicaciones de los segmentos individuales
de un programa. Un programa ordinario en modo protegido tiene tres segmentos:
código, datos y pila, y utiliza los registros de segmento CS,DS y SS:

◦ CS hace referencia a la tabla de descriptores para el segmento de código.


◦ DS hace referencia a la tabla de descriptores para el segmento de datos.
◦ SS hace referencia a la tabla de descriptores para el segmento de pila.
Modelo de varios segmentos
 En el modelo multisegmentos, cada tarea o
programa recibe su propia tabla de
descriptores de segmento, conocida como
tabla de descriptores locales (LDT). Cada
descriptor apunta a un segmento, que puede
ser distinto de los demás segmentos
utilizados por otros procesos. Cada segmento
tiene su propio espacio de direcciones.
Introducción al Lenguaje
Ensamblador

 El concepto de interrupciones
 Llamadas a servicios del sistema
El concepto de interrupciones
Las interrupciones son un mecanismo por medio del cual
hacemos que el CPU deje de hacer la tarea que estaba
realizando para que atienda otra tarea distinta (la que realiza
la interrupción).

Es decir, es una forma de llamar la atención del CPU de


manera que cuando cada dispositivo necesita ser atendido por
el CPU, emite una interrupción o señal haciendo que el CPU
vaya a atenderlo de inmediato.
Interrupciones en modo protegido
 En el modo protegido se usa un conjunto de 256 descriptores de
interrupción que están almacenados en una tabla de descriptores de
interrupciones (IDT: Interrupt Descriptor Table).

 La tabla de descriptores de interrupción tiene una longitud de 256 x 8


(2048) bytes, con cada descriptor conteniendo 8 bytes. La tabla de
descriptores de interrupciones está localizada en cualquier localidad de
memoria en el sistema especificada por el registro de direcciones de la
tabla de descriptores de interrupciones (IDTR: Interrupt Descriptor Table
Address Register).

 Cada entrada en la IDT contiene la dirección del procedimiento de servicio


de interrupción en la forma de un selector de segmento y una dirección
de desplazamiento de 32 bits. También contiene el bit P (presente) y los
bits DPL para describir el nivel de privilegio de la interrupción. La
siguiente figura muestra los contenidos del descriptor de interrupción.
Ejecución de interrupciones en modo
protegido
Para que una interrupción pueda ser servida o atendida por el
procesador, es necesario que se ejecuten una serie de pasos:
 
1. Terminar de ejecutar la instrucción actual en proceso.
2. Meter en la pila el registro de banderas.
3. Meter en la pila el la dirección del descriptor de segmento de la
próxima instrucción a ejecutar (CS).
4. Meter en la pila el desplazamiento de la próxima instrucción a
ejecutar (IP).
5. Determinar la dirección del manejador de la interrupción,
accesando la tabla de descriptores de interrupción. Se lee el
número de la interrupción, multiplicar por 8, accesar la tabla
en la posición correspondiente y cargar los registros CS e IP
con los valores.
6. Iniciar la ejecución del manejador de interrupciones.
Ejecución de interrupciones en modo
protegido
Todos los manejadores de interrupciones terminan con la
instrucción IRETD.

Después de ejecutar la instrucción IRETD se ejecutan los


siguientes pasos:
 
7. Recuperar el valor del registro IP desde la pila.
8. Recuperar el valor del registro CS desde la pila.
9. Recuperar el valor del registro de banderas desde la pila.
10. Continua la ejecución de la siguiente instrucción del
programa.
Interrupciones en modo protegido
 En el modo de 64 bits del Pentium 4 y Core 2,
una instrucción IRETQ debe ser usada para
regresar de una interrupción. Esta es una de
las razones por las que hay diferentes
sistemas operativos y controladores para el
modo de 64 bits.
Llamadas a servicios del sistema
 Las llamadas al sistema son interfaces de programación que sirven
para poder invocar los servicios que el sistema operativo nos ofrece.

 Estas llamadas se encuentran escritas en lenguajes de alto nivel


como C y C++.

 En general, las llamadas a sistemas son accesadas mediante una API


(interfaz de programación de aplicaciones), en vez de invocarlas
directamente, de ésta manera se hace más fácil el trabajo para un
programador de aplicaciones.

 Esta API especifica un conjunto de funciones que el programador


puede utilizar, incluyendo los parámetros que son pasados a cada
función y que retornan valores que el programador puede esperar
Llamadas a servicios del sistema
 A un programador le resulta más fácil utilizar una API que realizar las
llamadas al sistema directamente debido a que posee una mayor
portabilidad (cuando se desea compilar el programa en cualquier SO
que pueda soportar la API utilizada), y a menudo es más difícil trabajar
con las propias llamadas al sistema.

 El sistema de soporte en tiempo de ejecución, nos provee de una


interfaz de llamadas al sistema que sirve como enlace con las llamadas
al sistema disponibles en el sistema operativo. Ésta se encarga de
interceptar las llamadas a funciones dentro de la API e invoca a la
llamada al sistema necesaria. Cada llamada al sistema tiene asociado
un número y la interfaz mantiene una tabla indexada con dichos
números. Esta tabla sirve para invocar las llamadas al núcleo del SO y
retorna el estado de ejecución de la llamada al sistema y los valores
posibles de retorno.
Modos de direccionamiento
Los modos de direccionamiento indican la forma en que se obtiene el
operando de una instrucción. Los microprocesadores de la familia Intel
8086 tienen los siguientes modos de direccionamiento:
 
Direccionamiento por registro.- El operando se encuentra en uno de los
registros del CPU. Ejemplo: MOV EAX, EBX.
 
Direccionamiento inmediato.- El operando se encuentra
inmediatamente después de la instrucción. Ejemplo: MOV EAX,
12345678H.
 
Direccionamiento directo.- El operando se encuentra en la dirección de
memoria especificada directamente. Ejemplo: MOV EAX, [12345678H].
 
Modos de direccionamiento
Direccionamiento indirecto por registro .- El operando se encuentra en la
dirección de memoria especificada en un registro. Ejemplo: MOV EAX, [EBX].
 
Direccionamiento base más índice .- El operando se encuentra en la
dirección de memoria especificada por la suma de un registro base (EBX,
EBP) más un registro índice (ESI, EDI). Ejemplo: MOV EAX, [EBX + ESI]
 
Direccionamiento relativo por registro .- El operando se encuentra en la
dirección de memoria especificada por la suma de un registro base o un
registro índice más un desplazamiento. Ejemplo: MOV EAX, [EBX + 4].
 
Direccionamiento relativo base más índice .- El operando se encuentra en la
dirección de memoria especificada por la suma de un registro base más un
registro índice más un desplazamiento. Ejemplo: MOV EAX, [EBX + EDI + 4].
Modos de direccionamiento
Direccionamiento índice escalado.- Esta disponible en los procesadores
386 y superiores. El segundo registro de un par de ellos, el índice, se
modifica por el factor de escala 2X, 4X u 8X para generar la dirección de
memoria del operando. Ejemplo: MOV AL, [EAX + 4 * EBX].
 
Direccionamiento relativo RIP.- Este modo de direccionamiento sólo
está disponible al direccionamiento de extensión de 64 bits de los
procesadores actuales. Este modo permite el acceso a cualquier
localidad de memoria al agregar un desplazamiento de 32 bits al
contenido de 64 bits del puntero de instrucciones de 64 bits.

También podría gustarte