Сообщить разработчикам gcc?
Система Fedora 24, gcc version 6.3.1 20161221, параметры для компилятора -m64 -ffreestanding -O0 Компилирую, в том числе, следующий код
void set_int_handler(uint8 index, void *handler, uint8 type)
{
asm("pushf \n cli");
idt[index].selector = 8;
idt[index].address_0_15 = (size_t)handler & 0xFFFF;
idt[index].address_16_31 = (size_t)handler >> 16;
idt[index].type = type;
idt[index].reserved_IST = 0;
idt[index].address_32_63 = (size_t)handler >> 32;
idt[index].reserved2 = 0;
asm("popf");
}
Компилятор видит что внутри функции нет других вызовов и пропускает инструкцию выделения памяти в стеке (sub rsp, <размер>). Перемещает параметры на место локальных переменных и когда выполняется PUSHF, затирает эти параметры. Как это обойти я знаю. Нужно ли сообщать разработчикам gcc об ошибке, или это не ошибка. Может я неправильно пишу на СИ (может какой то параметр нужно указать компилятору?)
Ассемблерный листинг
set_int_handler:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
; копируем указатель стека в RBP
movq %rsp, %rbp
; здесь при -m32 sub rsp, <size>
.cfi_def_cfa_register 6
movl %edi, %ecx
movq %rsi, -16(%rbp)
movl %edx, %eax
movb %cl, -4(%rbp)
; gcc перемещает параметр в область локальных переменных
movb %al, -8(%rbp)
#APP
# 114 "interrupts.c" 1
; PUSHF затирает RBP - 4
pushf
Код для баг-репорта
#include <stdio.h>
short func(short p1, short p2, short p3)
{
asm("pushf \n popf");
return p1 + p2 + p3 + 1;
}
void main(void)
{
short a, b, c, d;
b = 3;
c = 4;
d = 5;
a = func(b, c, d);
printf("%d %d %d %d\n", a, b, c, d);
}
gcc -m64 -o main64 main.c
gcc -m32 -o main32 main.c
Ответы (1 шт):
Поддержка отреагировала на баг-репорт. Написали что я попал в red zone. Теория "Аблязов. Программирование на ассемблере для x86_64. стр.240 5.1.3 Модель вызова". Идея в следующем, предлагается для ускорения не использовать команду PUSH, а использовать MOV когда параметров у функции много (их через регистры передают, а число их конечно) их сохраняют таким образом в стек, предварительно выделив там место. Не уверен (см. док.) но соглашение о вызовах (64) предусматривает область в 128 байт (red zone) для параметров процедуры. gcc чтобы быть "быстрым" пишет туда, не выделяя память (мне это не нравится) т.е. не передвигая указатель стека (gcc -m32 это делает). Есть флаг -mno-red-zone который заставляет gcc передвинуть указатель стека. Это не ошибка а так задумано. Не попадайтесь на это.