El código de auto modificación siempre falla en la segmentación en Linux

Encontré un artículo sobre el código auto modificable e intenté hacer algunos ejemplos, pero siempre tengo fallas de segmentación. Tan rápido como puedo entender, hay una violación en los permisos de memoria. El segmento de código es (r) ead / e (x) ecute y, por lo tanto, el intento de escribir los resultados de esta falla. ¿Hay alguna forma de probar el programa cambiando los permisos de memoria en tiempo de ejecución o antes? Estoy usando Linux y el ejemplo está escrito en el ensamblaje GAS.

.extern memcpy
.section .data
string:
        .asciz  "whatever"
string_end:
.section .bss
        .lcomm buf, string_end-string
.section .text
.globl main
main:
        call changer
        mov $string, %edx
label:
        push string_end-string
        push $buf
        push $string
        call memcpy
changer:
        mov $offset_to_write, %esi
        mov $label, %edi
        mov $0xb, %ecx
loop1:
        lodsb
        stosb
        loop loop1
        ret
offset_to_write:
        push 0
        call exit
end:

así que después de la modificación sugerida por osgx, aquí hay un código que funciona. (En realidad, si ensamblas, enlazas y ejecutas, se bloquea, pero si ves usando gdb, ¡modifica su código!)

.extern memcpy
.section .data
string:
        .asciz  "Giorgos"
string_end:
.section .bss
        .lcomm buf, string_end-string
.section .text
.globl main
main:
        lea (main), %esi                # get the start of memory region to
                                        # change its permissions (smc-enabled)
        andl $0xFFFFF000, %esi          # align to start of a pagesize
        pushl   $7                      # permissions==r|w|x
        pushl   $4096                   # page size
        pushl   %esi                    # computed start address
        call    mprotect

        call    changer                 # function that does smc
        mov     $string, %edx
label:
        push    string_end-string       # this code will be overridden
        push    $buf                    # and never be executed!
        push    $string
        call    memcpy
changer:
        mov     $offset_to_write, %esi  # simple copy bytes algorithm
        mov     $label, %edi
        mov     $0xb, %ecx
loop1:
        lodsb
        stosb
        loop    loop1
        ret
offset_to_write:                        # these instructions will be
        push    $0                      # executed eventually
        call    exit
end:

Respuestas a la pregunta(3)

Su respuesta a la pregunta