Saltar al contenido

Suma de polinomios con código ensamblador x86-64

Sumar polinomios en lenguaje ensamblador

Esta semana he estado haciendo una práctica de ensamblador, consistia en sumar dos polinomios desde ensamblador pas ándole los parámetros desde C a ensamblador.

Primero definiremos la práctica para entender mejor el código. Tenemos dos polinomios de exponentes siempre positivos, y en este caso no más grandes de 20 términos, aunque esto es lo de menos se puede modificar facilmente en el código y adaptarlo al tamaño del polinomio que necesitemos.

Cada polinomio está formado por dos vectores uno tendrá el indice del coeficiente y otro el indice del exponente.

Por ejemplo así:

1
2
3
4
 int p_coef[20]={-16,+10,+18,+2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 //coeficientes del polinomio P
  int p_exp [20]={+15,+ 9,+ 5,+1,+0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 
//exponentes del polinomio P

Sería igual a este: -16*x^15 +10*x^9 +18*x^5 +2*x^1 -1*x^0

Los terminos “vacios” en el polinomio los hemos dejado como 0 ^-1, por lo tanto hemos rellenado las posiciones sin terminos con 0^1 hasta 20 que es el tamaño que hemos definido para el polinomio.

Si realizamos la suma de los dos polinomios p y q que tenemos declarados en el código obtendremos este resultado.

+1*x^10 -8*x^9 +5*x^8 +12*x^7

-16*x^15 +10*x^9 +18*x^5 +2*x^1 -1*x^0

————————————— ———————————————-
-16*x^15 +1*x^10 +2*x^9 +5*x^8 +12*x^7 +18*x^5 +2*x^1 -1*x^0

Segundo, ahora comentaremos como funciona el código. Para empezar declaramos en C los polinomios y creamos una función que mostrará el polinomio por pantalla.

1
2
3
4
5
6
7
8
9
10
  int p_coef[20]={-16,+10,+18,+2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
   //coeficientes del polinomio P
  int p_exp [20]={+15,+ 9,+ 5,+1,+0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 
   //exponentes del polinomio P
 
  int q_coef[20]={+0,+0,+0,+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
  int q_exp [20]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 
 
  int r_coef[20]={ +1,-8,+5,+12,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
  int r_exp [20]={+10,+9,+8, +7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

Función que mostrará el polinomio:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void p_print(int v_coef[], int v_exp[]){  
 
  if (v_exp[0]==-1) {
    printf ("Polinomi sense termes \n\n");
  }
  else {
    int i=0;
    while (v_exp[i]!=-1 && i<20) {
      if (v_coef[i]>=0) printf (" +"); else printf (" ");
      printf("%d*x^%d ",v_coef[i], v_exp[i]);
      i++;
    }
    printf("\n\n");
  }
}

Y por último llamamos al código escrito en ensamblador pasándole los parametros que queremos:

suma_ensamblador(r_coef,r_exp,p_coef,p_exp,q_coef,q_exp);

Es importante el orden en el que los ponemos, pues al código ensamblador le llegará el primer parametro a traves del registro rdi, el segundo llegará a rsi, y sucesivamente llegarán a rdx, rcx, r8 y por último r9.

Este es el código completo con comentarios escrito en C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
 
 
/** la función que mostrará el polinomio   **/
 
void p_print(int v_coef[], int v_exp[]){  
 
  if (v_exp[0]==-1) {
    printf ("Polinomi sense termes \n\n");
  }
  else {
    int i=0;
    while (v_exp[i]!=-1 && i<20) {
      if (v_coef[i]>=0) printf (" +"); else printf (" ");
      printf("%d*x^%d ",v_coef[i], v_exp[i]);
      i++;
    }
    printf("\n\n");
  }
}
 
 
int main() {  
/**
 * Programa Principal
*/
 
  int p_coef[20]={-16,+10,+18,+2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
  //coeficientes del polinomio P
  int p_exp [20]={+15,+ 9,+ 5,+1,+0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 
  //exponentes del polinomio P
 
  int q_coef[20]={+0,+0,+0,+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
  int q_exp [20]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 
 
  int r_coef[20]={ +1,-8,+5,+12,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
  int r_exp [20]={+10,+9,+8, +7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
 
 
  printf("Polinomio p(x)\n");
  p_print(p_coef, p_exp);
  printf("Polinomio q(x)\n");
  p_print(q_coef, q_exp);
 
 
  printf("******************************************\n");
 
  p_print(r_coef, r_exp);
  p_print(p_coef, p_exp);
 
  printf("---------------------------------------*\n");
  suma_ensamblador(r_coef,r_exp,p_coef,p_exp,q_coef,q_exp);
  p_print(q_coef, q_exp);
 
 
}

Este es el código comentado escrito en ensamblador para la arquitectura de 64bits (x86-64):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
section .data             
 
 
section .text                
 
  ; declaramos las subrutinas que queremos hacer visibles desde C                         
  global suma_ensamblador
 
 
 
 
 
; Sumaos dos polinomios. t(x)=r(x)+s(x)
 
; Paràmetres d'entrada : r_coef(rdi), r_exp(rsi),
;                        s_coef(rdx), s_exp(rcx),
;                        t_coef(r8 ), t_exp(r9 )    
 
suma_ensamblador:
 
 
  push rbp
  mov  rbp, rsp
  push rbx
  push r10
  push r11     ; guardamos los valores que queremos dejar intactos.
  push r12
  push r13
  push r14
 
  mov rax,-1
  mov r11,0 
  mov r10,0  ; para comparar  
 
  mov rbx,0  ;numero total de elementos en el polinomio
 
  mov r12,0  ;r
  mov r13,0  ;s
  mov r14,0  ;t
 
; r_coef(rdi), r_exp(rsi),
; s_coef(rdx), s_exp(rcx),
; t_coef(r8 ), t_exp(r9 )    
 
  inicio:
  cmp rbx,20
  je finalmal
 
  mov r10d,dword[rsi+r12*4]    ;exp r
  mov r11d,dword[rcx+r13*4]    ;exp s
 
 
  cmp r10d,r11d                ;comparamos los exponentes r y s
  jl r_menor
  je equals
 
 
  ; caso de que sea mayor r q s
  mov [r9+r14*4],r10d  ;movemos el exponente
 
  mov r10d, dword[rdi+r12*4] ;movemos el coeficiente
  mov [r8+r14*4],r10d
 
  inc rbx  ;numero total de elementos en el polinomio
 
  inc r12  ;r
  inc r14  ;t
 
  jmp inicio
 
  r_menor:
 
  mov [r9+r14*4],r11d  ;movemos el exponente
 
  mov r11d, dword[rdx+r13*4] ;movemos el coeficiente
  mov [r8+r14*4],r11d
 
  inc rbx  ;numero total de elementos en el polinomio
 
  inc r13  ;s
  inc r14  ;t
 
  jmp inicio
 
  equals:
  cmp r10d,-1
  je finalbien
 
  mov [r9+r14*4],r11d  ;movemos el exponente
 
  mov r11d, dword[rdx+r13*4] ;movemos el coeficiente de s
  mov [r8+r14*4],r11d
 
  mov r11d, dword[rdi+r12*4] ;movemos el coeficiente de r
  add [r8+r14*4],r11d        ;sumamos el coefciente de r a s
 
  inc rbx  ;numero total de elementos en el polinomio
  inc r12  ;r
  inc r13  ;s
  inc r14  ;t
 
  jmp inicio
 
  finalbien:
  mov rax,0
 
  finalmal:
 
  pop r14
  pop r13
  pop r12
  pop r11
  pop r10
  pop rbx
  mov rsp, rbp
  pop rbp
  ret

Entradas relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Comentarios (2)

Buenas, he estudiado los registros del cpu, los direccionamientos y como tambien las interrupciones(se que se inicia con .model small, .data y .code pero que más).
Me enseñaría hacer el codigo para sumar dos numeros decimales en ensamblador, por favor.
Gracias

Responder

Hola hahrukh.com,
Tienes algún ejemplo dentro de la web, no son con números decimales sino números enteros, pero creo que se puede adaptar fácilmente.
Un saludo,

Responder