Or how about some assembly?
main.c:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OUTPUT_LINE_LENGTH 76
#define INPUT_LINE_LENGTH (((OUTPUT_LINE_LENGTH)*3)/4)
void usage(char*);
int base64enc(char*, unsigned char*, int);
void usage(char *s)
{
fprintf(stderr, "Usage: %s [FILE]\n"
"If FILE is omitted or -, reads from the standard "
"input.\n", s);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
if (argc > 2) {
usage(argv[0]);
}
unsigned char ibuf[INPUT_LINE_LENGTH];
char obuf[OUTPUT_LINE_LENGTH+1]; /* +1 for terminating null */
FILE *ifile;
if (argc == 1 || strcmp(argv[1], "-") == 0) {
ifile = stdin;
} else {
ifile = fopen(argv[1], "r");
if (ifile == NULL) {
perror("Could not open input file");
exit(EXIT_FAILURE);
}
}
for (;;) {
int bytes_read = fread(ibuf, 1, INPUT_LINE_LENGTH, ifile);
if (bytes_read == 0) {
break;
}
int bytes_written = base64enc(obuf, ibuf, bytes_read);
obuf[bytes_written] = '\0';
puts(obuf);
}
fclose(ifile);
}
base64enc.S
Code:
.data
charmap:
.long 0x44434241
.long 0x48474645
.long 0x4c4b4a49
.long 0x504f4e4d
.long 0x54535251
.long 0x58575655
.long 0x62615a59
.long 0x66656463
.long 0x6a696867
.long 0x6e6d6c6b
.long 0x7271706f
.long 0x76757473
.long 0x7a797877
.long 0x33323130
.long 0x37363534
.long 0x2f2b3938
.text
.globl base64enc
.type base64enc, @function
base64enc:
pushl %ebp
movl %esp, %ebp
# Callee-save registers
pushl %ebx
pushl %edi
pushl %esi
# ebp-4 will be our temporary buffer
subl $4, %esp
# eax is the return value, which is the number of bytes written to
# the output buffer. Initialise it at 0.
movl $0, %eax
# ecx is the number of bytes left to be read. It is the third parameter
# to the function, so we fetch it from ebp+16.
movl 16(%ebp), %ecx
# edi is the address of the input buffer
movl 12(%ebp), %edi
# esi is the address of the output buffer
movl 8(%ebp), %esi
# If %ecx is already non-positive, don't enter the loop at all.
andl %ecx, %ecx
jle endmainloop
mainloop:
addl $4, %eax
movzbl (%edi), %edx
movl $0, %ebx
# More than one character?
cmpl $1, %ecx
jle nomorethanone
movzbl 1(%edi), %ebx
nomorethanone:
movb %bl, -4(%ebp)
# First base64 character
shrl $2, %edx
movzbl charmap(%edx), %edx
movb %dl, (%esi)
# Second base64 character
movzbl (%edi), %edx
andl $3, %edx
shll $4, %edx
shrl $4, %ebx
orl %ebx, %edx
movzbl charmap(%edx), %ebx
movb %bl, 1(%esi)
# More than one character? (Yes, we must do the test twice.)
cmpl $1, %ecx
jne morethanone
movw $0x3d3d, 2(%esi)
jmp endmainloop
morethanone:
movzbl -4(%ebp), %edx
movl $0, %ebx
# More than two characters?
cmpl $2, %ecx
jle nomorethantwo
movzbl 2(%edi), %ebx
nomorethantwo:
movb %bl, -4(%ebp)
# Third base64 character
andl $15, %edx
shll $2, %edx
shrl $6, %ebx
orl %ebx, %edx
movzbl charmap(%edx), %edx
movb %dl, 2(%esi)
# More than two characters? (Yes, again.)
cmpl $2, %ecx
jne morethantwo
movb $0x3d, 3(%esi)
jmp endmainloop
morethantwo:
# Fourth base64 character
movzbl -4(%ebp), %edx
andl $63, %edx
movzbl charmap(%edx), %edx
movb %dl, 3(%esi)
# Increment everything
addl $3, %edi
addl $4, %esi
subl $3, %ecx
# Exit?
andl %ecx, %ecx
jg mainloop
endmainloop:
# Clean-up
addl $4, %esp
popl %esi
popl %edi
popl %ebx
popl %ebp
ret
.size base64enc, .-base64enc
And this Makefile:
Code:
CC=gcc
CFLAGS=-m32 -std=c99 -pedantic -Wall -Werror
ifdef DEBUG
CFLAGS+=-g
endif
ASFLAGS=-m32
OBJECTS=main.o base64enc.o
OUTFILE=base64
$(OUTFILE): $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $+
clean:
rm -f $(OUTFILE) $(OBJECTS)
Performance is comparable to base64 from coreutils:
Code:
firas@aoba base64 % make
gcc -m32 -std=c99 -pedantic -Wall -Werror -c -o main.o main.c
gcc -m32 -c -o base64enc.o base64enc.S
gcc -m32 -std=c99 -pedantic -Wall -Werror -o base64 main.o base64enc.o
firas@aoba base64 % time base64 /boot/initrd.img-2.6.38-11-generic > test1.txt
base64 /boot/initrd.img-2.6.38-11-generic > test1.txt 0.05s user 0.36s system 98% cpu 0.417 total
firas@aoba base64 % time ./base64 /boot/initrd.img-2.6.38-11-generic > test2.txt
./base64 /boot/initrd.img-2.6.38-11-generic > test2.txt 0.15s user 0.35s system 90% cpu 0.550 total
firas@aoba base64 % diff test1.txt test2.txt
firas@aoba base64 %
I'm going to try and do it in MIPS assembly when I get my hands on my MIPS machine too. (Or maybe I should do a decoder...)
Bookmarks