У меня есть приложение, состоящее из кода 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
Просто показывает выдержку из кода, чтобы показать, как выполняется инициализация стека.