Вот этот код:
.intel_syntax noprefix

# Определяем секцию .rwplt как доступную для исполнения и записи
.section .rwplt, "axw"

# Экспортируем метки rwplt_start и stub0–stub5
.global rwplt_start, stub0, stub1, stub2, stub3, stub4, stub5

# Определяем rwplt_start как первую метку stub0
rwplt_start:

stub0:
    call fix_stub         # 5 байт

stub1:
    call fix_stub         # 5 байт

stub2:
    call fix_stub         # 5 байт

stub3:
    call fix_stub         # 5 байт

stub4:
    call fix_stub         # 5 байт

stub5:
    call fix_stub         # 5 байт

# Переходим к секции .text для определения fix_stub
.section .text
.global fix_stub
.type fix_stub, @function

fix_stub:
    # Пролог
    push    rbp
    mov     rbp, rsp
    sub     rsp, 16          # Выделение места на стеке

    # Шаг 1: Извлечение адреса возврата из стека
    mov     rax, [rbp + 8]   # [rbp+8] содержит адрес возврата (stubN +5)
    sub     rax, 5           # rax теперь указывает на stubN

    # Шаг 2: Вычисление N = (stubN - rwplt_start) / 5
    lea     rbx, [rip + rwplt_start]  # Загружаем адрес rwplt_start
    sub     rax, rbx          # rax = stubN - rwplt_start
    mov     ecx, 5            # Делитель
    xor     rdx, rdx          # Очищаем RDX для деления
    div     ecx               # rax = N, rdx = 0

    # Шаг 3: Вызов resolve(N)
    mov     edi, eax          # Перемещаем N в EDI (первый аргумент)
    call    resolve            # Вызов resolve(N), результат в RAX

    # Шаг 4: Вычисление rel32 = funcN - (stubN + 5)
    mov     rbx, rax          # rbx = funcN
    mov     rcx, [rbp + 8]    # rcx = stubN + 5
    sub     rbx, rcx          # rbx = funcN - (stubN + 5)
    mov     esi, ebx          # Перемещаем младшие 32 бита в esi (rel32)

    # Шаг 5: Перезапись stubN с помощью 'jmp rel32' (E9 <rel32>)
    mov     byte ptr [rax], 0xE9        # Opcode для JMP rel32
    mov     dword ptr [rax + 1], esi   # Записываем rel32

    # Шаг 6: Переход к funcN
    mov     rax, rbx          # rbx = funcN - (stubN + 5)
    add     rax, rcx          # rax = funcN
    jmp     rax               # Переход к funcN

    # Эпилог
    leave
    ret

Должен решать задачу:

В тестирующей программе имеется 6 подпрограмм func0, func1, ..., func5, адреса которых в памяти неизвестны, и подпрограмма void* resolve(int N), которая возвращает адрес подпрограммы funcN. К сожалению, resolve работает довольно медленно, и нам хотелось бы избежать лишних вызовов resolve.

Определите в сдаваемом файле секцию .rwplt, доступную для записи и исполнения кода, следующим образом:

.section .rwplt, "axw"
Определите в секции .rwplt 6 меток stub0, stub1, ..., stub5 таким образом, чтобы:

при первом вызове call stubN сначала вызывалась функция resolve(N), а затем происходил переход в функцию funcN;
при последующих вызовах call stubN сразу происходил переход в функцию funcN.
Указание: напишите в секции .text вспомогательную подпрограмму fix_stub, которая вызывает resolve и записывает после метки stubN новый машинный код.

Секция .rwplt должна иметь размер не более 48 байт. Секции .data (и других writeable секций) в сдаваемом файле быть не должно.

Гарантируется, что общий размер всех секций программы не превышает 2 ГБ.

Игнорируйте следующее предупреждение компоновщика:

/usr/bin/ld: warning: program has a LOAD segment with RWX permissions
Бонус: попробуйте обойтись 35 байтами в секции .rwplt.

Тестировать решение можно с помощью нижеследующего main.c, однако обратите внимание, что в тестирующей системе функции func[0-5] другие — например, у них могут быть разные наборы и типы параметров.

#include <stdio.h>

static int func0(int a, int b) {
    return a + b;
}
static int func1(int a, int b) {
    return a - b;
}
static int func2(int a, int b) {
    return a * b;
}
static int func3(int a, int b) {
    return a / b;
}
static int func4(int a, int b) {
    return a % b;
}
static int func5(int a, int b) {
    return a & b;
}
int stub0(int a, int b);
int stub1(int a, int b);
int stub2(int a, int b);
int stub3(int a, int b);
int stub4(int a, int b);
int stub5(int a, int b);

typedef int (*func_t)(int, int);
func_t funcs[] = {func0, func1, func2, func3, func4, func5};
func_t stubs[] = {stub0, stub1, stub2, stub3, stub4, stub5};

func_t resolve(unsigned a) {
    printf("resolve %u\n", a);
    return funcs[a];
}

int main() {
    int fn, a, b;
    while (scanf("%d %d %d", &fn, &a, &b) == 3) {
        int result = stubs[fn](a, b);
        printf("%d\n", result);
    }
    return 0;
}
      
 

Submit a solution

Language:	gas - GNU AS 11.3.0

Но при вводе:
0 1 2
Он выдает:
resolve 0
Segmentation fault
Вместо:
resolve 0
3

Ошибка возникает вот здесь:

    mov     byte ptr [rax], 0xE9        # Opcode для JMP rel32