Высокопроизводительная реализация функции форматированного вывода для C-программ, написанная на ассемблере x86-64. Оптимизированная, легковесная и расширяемая альтернатива стандартным библиотечным функциям.
__ __ _ _ _____ _ __
/ / / /__ (_)__ (_)__ / ___/__ __(_)__/ /__ ___
/ /_/ / _ \/ / _ \ / / _ \ \__ \/ / / / / _ / _ \/ _ \
\__,_/\___/_/_//_/_/ /\___/ /___/\_,_/_/\_,_/\___/_//_/
/___/
asm-putsf - это высокооптимизированная реализация функции форматированного вывода, написанная на ассемблере x86-64 для использования в C-программах без стандартной библиотеки.
typedef long long int int64_t;
extern void c_exit(int ret);
extern int64_t c_putsf(char *fmt, ...);
void _start(void) {
char *string = "PutsF";
int64_t decimal = 123;
char symbol = '!';
int64_t ret = c_putsf(
"{ %s, %d, %c }\n",
string, decimal, symbol
);
c_putsf("%d\n", ret); // 3
c_exit(0);
}
Проект создан для ситуаций, когда требуется минималистичная, но эффективная реализация форматированного вывода, например, в загрузчиках операционных систем, микроконтроллерах или в программах, не использующих стандартную библиотеку C.
Основные преимущества перед стандартными реализациями:
Поддерживаемые спецификаторы формата и особенности реализации
Эффективный вывод строк с прямым доступом к памяти. Использует системный вызов write для максимальной производительности.
puts_string:
push rbx
xor rbx, rbx
.next_iter:
cmp [rax+rbx], byte 0
je .close
push rax
mov rax, [rax+rbx]
call puts_char
pop rax
inc rbx
jmp .next_iter
Оптимизированный вывод целых чисел (64-бит) с использованием эффективных алгоритмов деления и преобразования в строку.
puts_decimal:
cmp rax, 0
jl .is_minus
.next_iter:
mov rbx, 10
xor rdx, rdx
div rbx
push rdx
inc rcx
cmp rax, 0
je .puts_iter
jmp .next_iter
Минималистичный вывод отдельных символов с прямым системным вызовом, минуя буферизацию.
puts_char:
push rax
mov rsi, rsp
mov rdi, 1
mov rdx, 1
mov rax, 1
call do_syscall
pop rax
ret
Поддержка вывода символа процента через экранирование. Простая и эффективная реализация.
cmp [rax], byte '%'
je .special_char
...
.special_char:
inc rax
cmp [rax], byte '%'
je .default_char
Системный дизайн и алгоритмы работы putsf
Посимвольная обработка входной строки формата. Поиск спецификаторов '%'.
Для каждого найденного спецификатора определяется тип данных и выбирается соответствующая функция вывода.
Аргументы извлекаются из стека в соответствии с соглашениями о вызовах SysV x64.
Вызов специализированных функций: puts_string, puts_decimal, puts_char.
Прямое взаимодействие с ядром через syscall для вывода данных.
Функция возвращает количество обработанных символов.
Для преобразования чисел в строку используется алгоритм последовательного деления на 10. Каждая итерация дает одну цифру в обратном порядке:
digits = []
while num > 0:
digit = num % 10
num = num // 10
digits.append(digit)
Где:
num - исходное число
digit - очередная цифра (от младшего разряда к старшему)
Для отрицательных чисел сначала выводится знак '-', затем число преобразуется в положительное. Особенность реализации - работа непосредственно с регистрами процессора, без промежуточных преобразований.
Сравнение с другими реализациями форматированного вывода
Быстрый старт с asm-putsf в вашем проекте
Склонируйте репозиторий проекта:
git clone https://github.com/alexeev-prog/asm-putsf.git
cd asm-putsf
Соберите проект с помощью Makefile:
make build clean
Или соберите вручную:
fasm src/putsf.asm bin/putsf.o
fasm src/c_putsf.asm bin/c_putsf.o
fasm src/c_exit.asm bin/c_exit.o
gcc -nostdlib -o bin/putsf.bin bin/putsf.o bin/c_putsf.o \
bin/c_exit.o your_program.c
Запустите скомпилированный бинарник:
./bin/putsf.bin