Изменен указатель стека и C библиотечные вызовы - PullRequest
1 голос
/ 22 января 2020

У меня есть приложение, состоящее из кода C и сборки x64.

В начале основной функции (записано в C) выделяется виртуальная память. Затем вызывается процедура сборки. В этой процедуре указатель стека изменяется на выделенную память. Процедура сборки в конечном итоге вызывает такие функции, как write (), printf (), fflu sh ().

Когда вызывается printf (), за которым следует fflu sh (), иногда происходит сбой программы, а иногда пишет неправильные символы в стандартный вывод.

Когда я удаляю код для изменения указателя стека, проблема исчезнет.

Существуют ли какие-либо особенности обработки указателей стека для Windows программ?

Примечание. Я знаю о выделении 32 байтов «теневого пространства» в стеке до вызова функций C из сборки.

Я использую cygwin и g cc для сборки программы.

main. c:

#include <stdio.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <windows.h>
#include <string.h>

#define wordSize 8
#define fixnumShift 0x02
typedef uint64_t ptr;

extern int schemeEntry();

char* allocateProtectedSpace(int size) {
    SYSTEM_INFO si;
    GetSystemInfo(&si);
    int pageSize = si.dwPageSize;
    int aligned = (size + pageSize - 1) / pageSize * pageSize;
    int total = aligned + pageSize * 2;
    char* pBase = (char*) VirtualAlloc(0, total, MEM_RESERVE, PAGE_NOACCESS);
    char* pSpace = (char*) VirtualAlloc(pBase + pageSize, aligned, MEM_COMMIT, PAGE_READWRITE);
    return pSpace;
}

void printPtr(ptr p) {
    int n = (int) p;
    printf("%d", n >> fixnumShift);
    fflush(stdout);
}

int main() {
    int stackSize = 16 * 4096;
    char* stack = allocateProtectedSpace(stackSize);
    char* stackHigherAddr = stack + stackSize - wordSize;
    printPtr(schemeEntry(stackHigherAddr));
    return 0;
}

schemeMain.s

    .text
    .globl schemeEntry
    schemeEntry:
    pushq %r15
    movq %rsp, %r15
    movq %rcx, %rsp
    pushq %rbp
    pushq %r15
    pushq %r14
    pushq %r13
    pushq %r12
    pushq %rbx

    subq $104, %rsp

    movq $4, 96(%rsp)
    movq 96(%rsp), %rcx
    subq $32, %rsp
    call printPtr
    addq $32, %rsp

    addq $104, %rsp

    popq %rbx
    popq %r12
    popq %r13
    popq %r14
    popq %r15
    popq %rbp
    movq %r15, %rsp
    popq %r15
    retq

Просто показывает выдержку из кода, чтобы показать, как выполняется инициализация стека.

1 Ответ

0 голосов
/ 23 января 2020

Проблема была решена путем поддержания 16-байтового выравнивания для указателя стека.

...