commit dc685b3d93a34e5ff821be063d8e8bda945c6876 Author: sweetbread Date: Sun Jun 11 03:21:00 2023 +0300 Init commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d177d6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.gox +*.kex \ No newline at end of file diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..2ddfcaa --- /dev/null +++ b/example/Makefile @@ -0,0 +1,26 @@ +PROGRAM=example +OBJS=../syscalls.o ../runtime.go.o colors.go.o colors.gox ../kos.go.o ../kos.gox $(PROGRAM).go.o +GOFLAGS=-m32 -c -nostdlib -nostdinc -fno-stack-protector -fno-split-stack -static -fno-leading-underscore -fno-common -fno-pie -I. +GO=gccgo +ASFLAGS=-g -f elf32 -F dwarf +NASM=nasm $(ASFLAGS) +OBJCOPY=objcopy +LDFLAGS=-n -T ../static.lds -m elf_i386 --no-ld-generated-unwind-info + +all: $(OBJS) link + +clean: + rm -f $(OBJS) $(PROGRAM).kex + +link: + ld $(LDFLAGS) -o $(PROGRAM).kex $(OBJS) + $(OBJCOPY) $(PROGRAM).kex -O binary + +%.gox: %.go.o + $(OBJCOPY) -j .go_export $< $@ + +%.go.o: %.go + $(GO) $(GOFLAGS) -o $@ -c $< + +%.o: %.asm + $(NASM) $< diff --git a/example/colors.go b/example/colors.go new file mode 100644 index 0000000..f08f455 --- /dev/null +++ b/example/colors.go @@ -0,0 +1,20 @@ +package colors + +const( + Black = 0x000000 + Gray = 0x808080 + Silver = 0xc0c0c0 + White = 0xffffff + Fuchsia = 0xff00ff + Purple = 0x800080 + Red = 0xff0000 + Maroon = 0x800000 + Yellow = 0xffff00 + Olive = 0x808000 + Lime = 0x00ff00 + Green = 0x008000 + Aqua = 0x00ffff + Teal = 0x008080 + Blue = 0x0000ff + Navy =0x000080 +) diff --git a/example/example.go b/example/example.go new file mode 100644 index 0000000..1452596 --- /dev/null +++ b/example/example.go @@ -0,0 +1,79 @@ +package example + +import ( + "colors" + "../kos" +) + +const ( + Btn1 = 2 + Btn2 = 3 + BtnExit = 1 +) + +type Button struct { + label string + x int + y int + id int +} + +func NewButton(label string, x int, y int, id int) Button { + return Button{ + label: label, + x: x, + y: y, + id: id, + } +} + +func (button *Button) make() { + kos.CreateButton(button.x, button.y, len(button.label)*15, 30, button.id, colors.Blue) + kos.WriteText(button.x, button.y, 0x11000000|colors.White, button.label) +} + +func RedrawAll(barPos int) { + + kos.Redraw(1) + kos.Window(500, 250, 420, 200, "GoLang") + kos.DrawLine(32, 80, 150, 80, colors.Green) + kos.DrawBar(barPos, 90, 100, 30, colors.Red) + + str1 := "123" + str2 := "222" + + if str1 == str2 || str2 == "222" { + kos.WriteText(50,50,0,"==") + } else { + kos.WriteText(50,50,0,"!=") + } + + b1 := NewButton(" <- ", 32, 128, Btn1) + b1.make() + + b2 := NewButton(" -> ", 310, 128, Btn2) + b2.make() + +} + +func Main() { + pos := 160 + + for { + switch kos.Event() { + case kos.EVENT_REDRAW: + RedrawAll(pos) + case kos.EVENT_BUTTON: + switch kos.GetButtonID() { + case Btn1: + pos -= 32 + RedrawAll(pos) + case Btn2: + pos += 32 + RedrawAll(pos) + case BtnExit: + kos.Exit() + } + } + } +} diff --git a/kos.go b/kos.go new file mode 100644 index 0000000..7934dc7 --- /dev/null +++ b/kos.go @@ -0,0 +1,34 @@ +package kos + +const ( + EVENT_NONE = 0 /* Очередь событий пуста */ + EVENT_REDRAW = 1 /* Окно и его элементы должны быть перерисованы */ + EVENT_KEY = 2 /* Была нажата клавиша на клавиатуре */ + EVENT_BUTTON = 3 /* Была нажата кнопка мыши */ + EVENT_DESKTOP = 5 /* Завершена перерисовка рабочего стола */ + EVENT_MOUSE = 6 /* Обнаружена активность мыши (движение, нажатие кнопки) */ + EVENT_IPC = 7 /* Уведомление о межпроцессорном взаимодействии */ + EVENT_NETWORK = 8 /* Событие сети */ + EVENT_DEBUG = 9 /* Событие отладочной подсистемы */ + EVENT_IRQBEGIN = 16 /* Начало обработки прерывания */ +) + +func Sleep(ms uint32) __asm__("go.kos.Sleep"); +func GetTime() uint32 __asm__("go.kos.GetTime"); +func Event() int __asm__("go.kos.Event"); +func GetButtonID() int __asm__("go.kos.GetButtonID"); +func CreateButton(x, y, xsize, ysize, id int, color uint32) __asm__("go.kos.CreateButton"); +func Exit() __asm__("go.kos.Exit"); +func Redraw(id int) __asm__("go.kos.Redraw"); +func Window(y, x, w, h int, title string) __asm__("go.kos.Window"); +func WriteText(x, y int, color uint32, text string) __asm__("go.kos.WriteText"); +func WriteText2(x, y, color1, color2 uint32) __asm__("go.kos.WriteText2"); +func DrawLine(x1, y1, x2, y2 int, color uint32) uint32 __asm__("go.kos.DrawLine"); +func DrawBar(x, y, xsize, ysize int, color uint32) __asm__("go.kos.DrawBar"); +func DebugOutHex(value uint32) __asm__("go.kos.DebugOutHex"); +func DebugOutChar(ch byte) __asm__("go.kos.DebugOutChar"); +func DebugOutStr(str string) __asm__("go.kos.DebugOutStr"); + +//func Pointer2byteSlice(ptr uint32) *[]byte __asm__("__unsafe_get_addr"); + +//func Pointer2uint32(ptr interface{}) uint32 __asm__("__unsafe_get_addr"); diff --git a/runtime.go b/runtime.go new file mode 100644 index 0000000..d3762c5 --- /dev/null +++ b/runtime.go @@ -0,0 +1,180 @@ +package runtime + +import ( + "unsafe" +) + +func malloc(size uint32) unsafe.Pointer __asm__("malloc"); + +func MemMove(dest, src []byte, n int) { + if dest == nil || src == nil { + return + } + + if len(dest) < n || len(src) < n { + return + } + + equal := true + for i := 0; i < n; i++ { + if dest[i] != src[i] { + equal = false + break + } + } + + if equal { + return + } + + for i := 0; i < n; i++ { + dest[i] = src[i] + } +} + +func Memcmp(a, b []byte) int { + lenA := len(a) + lenB := len(b) + minLen := lenA + if lenB < minLen { + minLen = lenB + } + + // Преобразуем срезы байтов в указатели на память + ptrA := (*int32)(unsafe.Pointer(&a[0])) + ptrB := (*int32)(unsafe.Pointer(&b[0])) + + // Сравниваем по 4 байт (размер int32) за раз + for i := 0; i < minLen/4; i++ { + if *ptrA != *ptrB { + // Если найдены различающиеся байты, возвращаем результат сравнения + if *ptrA < *ptrB { + return -1 + } else { + return 1 + } + } + ptrA = (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(ptrA)) + unsafe.Sizeof(*ptrA))) + ptrB = (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(ptrB)) + unsafe.Sizeof(*ptrB))) + } + + // Если длины срезов отличаются, возвращаем результат сравнения длин + if lenA < lenB { + return -1 + } else if lenA > lenB { + return 1 + } + + return 0 +} + +func MemEqual32(a, b []byte) bool { + if len(a) != len(b) { + return false + } + + for i := 0; i < len(a)/4; i++ { + offset := i * 4 + valA := uint32(a[offset])<<24 | uint32(a[offset+1])<<16 | uint32(a[offset+2])<<8 | uint32(a[offset+3]) + valB := uint32(b[offset])<<24 | uint32(b[offset+1])<<16 | uint32(b[offset+2])<<8 | uint32(b[offset+3]) + + if valA != valB { + return false + } + } + + return true +} + +func MemEqual8(dest, src []byte, n int) bool { + if len(dest) < n || len(src) < n { + return false + } + + for i := 0; i < n; i++ { + if dest[i] != src[i] { + return false + } + } + + return true +} + +func StrEqual(a, b string) bool { + if len(a) != len(b) { + return false + } + + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + + return true +} + +func ConcatStrings(strs ...string) string { + totalLen := 0 + for _, str := range strs { + totalLen += len(str) + } + + result := make([]byte, totalLen) + offset := 0 + for _, str := range strs { + copy(result[offset:], []byte(str)) + offset += len(str) + } + + return string(result) +} + +func SliceBytetoString(slice []byte) string { + str := "" + for _, b := range slice { + str += string(b) + } + return str +} + +func IntString(n int) string { + if n == 0 { + return "0" + } + + var result string + isNegative := false + + if n < 0 { + isNegative = true + n = -n + } + + for n > 0 { + digit := n % 10 + result = string('0'+digit) + result + n /= 10 + } + + if isNegative { + result = "-" + result + } + + return result +} + +func StringToSliceByte(str string) []byte { + slice := make([]byte, len(str)) + for i := 0; i < len(str); i++ { + slice[i] = str[i] + } + return slice +} + + + +func MakeSlice(et *uint32, len, cap int) unsafe.Pointer { + + return malloc(0x1000) +} \ No newline at end of file diff --git a/static.lds b/static.lds new file mode 100644 index 0000000..9c08bc0 --- /dev/null +++ b/static.lds @@ -0,0 +1,42 @@ +SECTIONS +{ + . = 0x00000; + + .text : + { + LONG(0x554E454D); + LONG(0x31305445); + LONG(1); + LONG(start_program); + LONG(__end); + LONG(0x10000); + LONG(0x10000); + LONG(0); + LONG(0); + *(.text) + } + + .eh_frame : + { + *(.eh_frame) + } + + .group : + { + *(.group) + } + + .data : + { + *(.data) + } + + .rodata : + { + *(.rodata) + *(.rodata.*) + } + + + __end = .; +} diff --git a/syscalls.asm b/syscalls.asm new file mode 100644 index 0000000..5730aef --- /dev/null +++ b/syscalls.asm @@ -0,0 +1,316 @@ +SECTION .text + +global runtime.goPanicIndex + +runtime.goPanicIndex: + ret + +global runtime.goPanicSliceB +runtime.goPanicSliceB: + ret + +global memcmp +extern go_0runtime.Memcmp + +memcmp: + call go_0runtime.Memcmp + ret + +global memmove +extern go_0runtime.MemMove + +memmove: + call go_0runtime.MemMove + ret + +global runtime.memequal32..f +extern go_0runtime.MemEqual32 + +runtime.memequal32..f: + call go_0runtime.MemEqual32 + ret + +global runtime.memequal8..f +extern go_0runtime.MemEqual8 + +runtime.memequal8..f: + call go_0runtime.MemEqual8 + ret + +global runtime.strequal..f +extern go_0runtime.StrEqual + +runtime.strequal..f: + call go_0runtime.StrEqual + ret + +global runtime.concatstrings +extern go_0runtime.ConcatStrings + +runtime.concatstrings: + call go_0runtime.ConcatStrings + ret + +global runtime.slicebytetostring +extern go_0runtime.SliceBytetoString + +runtime.slicebytetostring: + call go_0runtime.SliceBytetoString + ret + +global runtime.intstring +extern go_0runtime.IntString + +runtime.intstring: + call go_0runtime.IntString + ret + +global runtime.stringtoslicebyte +extern go_0runtime.StringToSliceByte + +runtime.stringtoslicebyte: + call go_0runtime.StringToSliceByte + ret + +global runtime.makeslice +extern go_0runtime.MakeSlice + +runtime.makeslice: + call go_0runtime.MakeSlice + ret + +global malloc +malloc: + push ebp + mov ebp, esp + mov eax, 68 + mov ebx, 12 + mov ecx, dword [esp + 8] ; Параметр size передается через стек + int 0x40 + mov esp, ebp + pop ebp + ret ; Возвращаемое значение находится в регистре EAX + +global go.kos.Sleep +global go.kos.Event +global go.kos.GetButtonID +global go.kos.CreateButton +global go.kos.Exit +global go.kos.Redraw +global go.kos.Window +global go.kos.WriteText +global go.kos.GetTime +global go.kos.DrawLine +global go.kos.DrawBar +global go.kos.DebugOutHex +global go.kos.DebugOutChar +global go.kos.DebugOutStr +global go.kos.WriteText2 + +go.kos.Sleep: + push ebp + mov ebp, esp + mov eax, 5 + mov ebx, [ebp+8] + int 0x40 + mov esp, ebp + pop ebp + ret + + +go.kos.Event: + mov eax, 10 + int 0x40 + ret + +go.kos.GetButtonID: + mov eax, 17 + int 0x40 + test al, al + jnz .no_button + shr eax, 8 + ret +.no_button: + xor eax, eax + dec eax + ret + +go.kos.Exit: + mov eax, -1 + int 0x40 + ret + +go.kos.Redraw: + push ebp + mov ebp, esp + mov eax, 12 + mov ebx, [ebp+8] + int 0x40 + mov esp, ebp + pop ebp + ret + +go.kos.Window: + push ebp + mov ebp, esp + mov ebx, [ebp+8] + shl ebx, 16 + or ebx, [ebp+16] + mov ecx, [ebp+12] + shl ecx, 16 + or ecx, [ebp+20] + mov edx, 0x14 + shl edx, 24 + or edx, 0xFFFFFF + mov esi, 0x808899ff + mov edi, [ebp+24] + xor eax, eax + int 0x40 + mov esp, ebp + pop ebp + ret + +go.kos.WriteText: + push ebp + mov ebp, esp + mov eax, 4 + mov ebx, [ebp+8] + shl ebx, 16 + mov bx, [ebp+12] + mov ecx, [ebp+16] + mov edx, [ebp+20] + mov esi, [ebp+24] + int 0x40 + mov esp, ebp + pop ebp + ret + +go.kos.WriteText2: + push ebp + mov ebp, esp + mov eax, 47 + mov ebx, [ebp+8] + shl ebx, 16 + mov ecx, [ebp+12] + mov edx, [ebp+20] + shl edx, 16 + add edx, [ebp+24] + mov esi, [ebp+28] + int 0x40 + mov esp, ebp + pop ebp + ret + +go.kos.DrawLine: + push ebp + mov ebp, esp + mov ebx, [ebp+8] + shl ebx, 16 + mov bx, [ebp+16] + mov ecx, [ebp+12] + shl ecx, 16 + mov cx, [ebp+20] + mov edx, [ebp+24] + mov eax, 38 + int 0x40 + mov esp, ebp + pop ebp + ret + +go.kos.DrawBar: + push ebp + mov ebp, esp + mov eax, 13 + mov ebx, [ebp+8] + shl ebx, 16 + mov bx, [ebp+16] + mov ecx, [ebp+12] + shl ecx, 16 + mov cx, [ebp+20] + mov edx, [ebp+24] + int 0x40 + mov esp, ebp + pop ebp + ret + +go.kos.GetTime: + mov eax, 3 + int 0x40 + ret + +go.kos.DebugOutHex: + mov eax, [esp+4] + mov edx, 8 +new_char: + rol eax, 4 + movzx ecx, al + and cl, 0x0f + mov cl, [__hexdigits + ecx] + pushad + mov eax, 63 + mov ebx, 1 + int 0x40 + popad + dec edx + jnz new_char + ret + +go.kos.DebugOutChar: + mov al, [esp+4] + pushf + pushad + mov cl, al + mov eax, 63 + mov ebx, 1 + int 0x40 + popad + popf + ret + +go.kos.DebugOutStr: + mov edx, [esp+4] + mov eax, 63 + mov ebx, 1 +m2: + mov cl, [edx] + test cl, cl + jz m1 + int 40h + inc edx + jmp m2 +m1: + ret + +go.kos.CreateButton: + push ebp + mov ebp, esp + mov eax, 8 + mov ebx, [ebp+8] + shl ebx, 16 + mov bx, [ebp+16] + mov ecx, [ebp+12] + shl ecx, 16 + mov cx, [ebp+20] + mov edx, [ebp+24] + mov esi, [ebp+28] + int 0x40 + mov esp, ebp + pop ebp + ret + +extern go_0example.Main +global start_program +start_program: + mov eax, 68 + mov ebx, 11 + int 0x40 + call go_0example.Main + + +SECTION .data +__hexdigits: + db '0123456789ABCDEF' + +__test: + dd __hexdigits + dd 15