jeudi 14 janvier 2021

Chapitre 92 : assembleur 32 bits : nouvelle gestion du tas

 

Bon, j’ai fait une énorme erreur dans cette découverte de l’assembleur. En effet j’ai utilisé l’appel système Linux BRK pour gérer l’allocation de place sur le tas lorsque j’avais besoin d’allouer de la place dynamiquement. Or en relisant la documentation de cet appel, je me suis aperçu que cette fonction était faite pour allouer de la place supplémentaire à un processus !!!

Donc j’ai repris l’étude de cette fonctionnalité pour ne plus utiliser BRK. La première idée est de déclarer une zone banalisée de plusieurs milliers d’octets et de gérer cet espace à l’aide d’un pointeur. C’est ce que j’ai fait dans le programme resTas32. Pour être tranquille, il suffit de définir la zone banalisée avec une taille suffisante pour les besoins d’un programme.

L’inconvénient de cette solution est qu’il faut définir cette zone et dupliquer le code pour gérer le tas dans chaque programme.

Une autre idée est d’utiliser l’espace après la fin de la section bss. J’ai testé l’écriture d‘une donnée dans cette partie de la mémoire. Cela fonctionne mais ce n’est pas très propre car cela peut entraîner une interférence si le programme appelle des fonctions de librairies externes car la place utilisée n’est pas référencée.

Enfin une autre solution que j’ai adoptée, c’est de déclarer une zone tas lors de l’édition du lien. Cette zone mémoire sera réservée en fin de la section bss. Pour cela il faut créer un script ld qui sera appelé par le linker :

Voici son contenu :

SECTIONS

{

PROVIDE(__executable_start = 0x0010000);

. = 0x00010000 + SIZEOF_HEADERS;

.interp : { *(.interp) }

.note.ABI-tag : { *(.note.ABI-tag) }

.hash : { *(.hash) }

.dynsym : { *(.dynsym) }

.dynstr : { *(.dynstr) }

.version : { *(.version) }

.version_d : { *(.version_d) }

.version_r : { *(.version_r) }

.rel.dyn : { *(.rel.dyn) }

.rela.dyn : { *(.rela.dyn) }

.rel.plt : { *(.rel.plt) }

.rela.plt : { *(.rela.plt) }

.init : { KEEP (*(.init)) }

.plt : { *(.plt) }

.text : { *(.text .text.*) }

.fini : { KEEP (*(.fini)) }

PROVIDE(__etext = .);

PROVIDE(_etext = .);

PROVIDE(etext = .);

.rodata : { *(.rodata .rodata.*) }

__exidx_start = .;

.ARM.exidx : { *(.ARM.exidx*) }

__exidx_end = .;

. = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1));

. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));

.tdata : { *(.tdata .tdata.*) }

.tbss : { *(.tbss .tbss.*) }

.preinit_array :

{

PROVIDE_HIDDEN (__preinit_array_start = .);

KEEP (*(.preinit_array))

PROVIDE_HIDDEN (__preinit_array_end = .);

}

.init_array :

{

PROVIDE_HIDDEN (__init_array_start = .);

KEEP (*(.init_array*))

PROVIDE_HIDDEN (__init_array_end = .);

}

.fini_array :

{

PROVIDE_HIDDEN (__fini_array_start = .);

KEEP (*(.fini_array*))

PROVIDE_HIDDEN (__fini_array_end = .);

}

.dynamic : { *(.dynamic) }

.got : { *(.got.plt) *(.got) }

.data :

{

__data_start = 0x20000;

*(.data .data.*)

}

_edata = .;

PROVIDE(edata = .);

__bss_start = .;

__bss_start__ = .;

.bss :

{

*(.bss .bss.*)

. = ALIGN(. != 0 ? 32 / 8 : 1);

}

__bss_end__ = .;

_bss_end__ = .;

.heap (NOLOAD):

{

TAILLETAS = DEFINED(TAILLETAS) ? TAILLETAS : 0x20000 ;

. = ALIGN(8);

heap_begin = .;

. = . + TAILLETAS;

. = ALIGN(8);

heap_end = .;

}

. = ALIGN(4);

__end = .;

_end = .;

PROVIDE(end = .);

}

 

Vous remarquerez que j’utilise une instruction pour définir la taille du tas par défaut si celle çi n’est pas définie par un programme utilisateur. Attention dans le programme utilisateur il faudra aussi indiquer que le symbole TAILLETAS est global.

Le script est appelé par le linker avec l’option -T ~/scripts/linkerldarm.ld.



Voir son utilisation dans le programme : verifTas32.s

Dans ce programme, nous faisons appel à des routines regroupées dans le fichier routinesARM2021.s. Nous trouvons une routine pour réserver la place sur le tas, une routine pour libérer la place et une routine d’insertion d’une chaîne de caractères dans une autre chaîne.

La routine pour libérer la place doit être utilisée à bon escient. En effet ici, il n’est possible de libérer de la place que dans l’ordre inverse de la réservation si nous voulons réutiliser la place.

Il ne reste plus qu'à adapter cette solution pour le 64 bits.