diff options
| author | onelin <oscar@nelin.dk> | 2026-06-10 04:58:13 +0000 |
|---|---|---|
| committer | onelin <oscar@nelin.dk> | 2026-06-10 04:58:13 +0000 |
| commit | 7cc1a2e6ccc8f4a87e73c35672e7bb973e965470 (patch) | |
| tree | ce65f72b384f9d75d15cc68ed2f0225e2b21ae0b | |
Initial commit
| -rw-r--r-- | .clang-format | 239 | ||||
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | instructions.h | 76 | ||||
| -rw-r--r-- | main.c | 8 | ||||
| -rw-r--r-- | registers.h | 76 | ||||
| -rw-r--r-- | tiny.s | 11 | ||||
| -rw-r--r-- | write_elf.c | 141 |
7 files changed, 561 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..451482f --- /dev/null +++ b/.clang-format @@ -0,0 +1,239 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Right +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseColons: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: AllDefinitions +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +KeepEmptyLinesAtEOF: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9f3c9a5 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +.PHONY: fmt + +write-elf: main.c write_elf.c registers.h instructions.h + gcc -static-pie main.c -o write-elf + +tiny: tiny.s + nasm -f elf64 tiny.s + +fmt: main.c write_elf.c registers.h instructions.h + clang-format -i $^ diff --git a/instructions.h b/instructions.h new file mode 100644 index 0000000..9727137 --- /dev/null +++ b/instructions.h @@ -0,0 +1,76 @@ +#ifndef INSTRUCTIONS_H +#define INSTRUCTIONS_H + +// Prefixes +// Prefix groups are mutually exclusive + +// Prefix group 1 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNE 0xf2 +#define PREFIX_REPNZ PREFIX_REPNE +#define PREFIX_REP 0xf3 +#define PREFIX_REPE PREFIX_REP +#define PREFIX_REPZ PREFIX_REP + +// Prefix group 2 +#define PREFIX_OVERRIDE_SEGMENT_CS 0x2e +#define PREFIX_OVERRIDE_SEGMENT_SS 0x36 +#define PREFIX_OVERRIDE_SEGMENT_DS 0x3e +#define PREFIX_OVERRIDE_SEGMENT_ES 0x26 +#define PREFIX_OVERRIDE_SEGMENT_FS 0x64 +#define PREFIX_OVERRIDE_SEGMENT_GS 0x65 +#define PREFIX_BRANCH_NOT_TAKEN PREFIX_OVERRIDE_SEGMENT_CS +#define PREFIX_BRANCH_TAKEN PREFIX_OVERRIDE_SEGMENT_DS + +// Prefix group 3 +#define PREFIX_OVERRIDE_OPSIZE 0x66 + +// Prefix group 4 +#define PREFIX_OVERRIDE_ADDRESSSIZE 0x67 + +// Instructions +// Move double-word immediate +#define MOVBI(reg, imm) (0xb0 + reg), (imm & 0xff) +#define MOVWI(reg, imm) \ + (0xb8 + reg), (imm & 0xff), ((imm >> 8) & 0xff), ((imm >> 16) & 0xff) +#define MOVDI(reg, imm) \ + (0xb8 + reg), (imm & 0xff), ((imm >> 8) & 0xff), ((imm >> 16) & 0xff), \ + ((imm >> 24) & 0xff) +// TODO replace 0x48 with encoding, +// | 0 1 0 0 | W R X B | +// +// 0 1 0 0 -- fixed pattern +// W -- Set to use 64-bit operands, +// R -- extension to MODRM.reg field, registers +// X -- extension to SIB.index field, 64-bit addressing +// B -- extension to MODRM.rm or SIB.base field, 64-bit addressing +#define MOVABS(reg, imm) 0x48, MOVD(reg, imm) +#define MOVQ(reg, imm) 0x48, 89 c8 + +#define ADD +#define CALL +#define CMP +#define DEC +#define DIV +#define HLT +#define IDIV +#define IMUL +#define INC +#define INT +#define INTO +#define IRET +#define JNZ +#define JMP +#define LEA +#define POP +#define PUSH +#define RET +#define RETN +#define SUB +#define XOR + +#define SYSCALL 0x0f, 0x05 + +#define REX(mode) (0b01000000 | mode) + +#endif @@ -0,0 +1,8 @@ +#include "write_elf.c" + +int +main(int argc, char* argv[]) { + char opcodes[] = {}; + write_elf("test.out", some_opcodes_len, some_opcodes); + return 0; +} diff --git a/registers.h b/registers.h new file mode 100644 index 0000000..1f3b040 --- /dev/null +++ b/registers.h @@ -0,0 +1,76 @@ +#ifndef REGISTERS_H +#define REGISTERS_H + +// 8-bit global pointer +#define REG_AL 0 +#define REG_CL 1 +#define REG_DL 2 +#define REG_BL 3 +#define REG_AH 4 +#define REG_CH 5 +#define REG_DH 6 +#define REG_BH 7 +#define REG_R8L 8 +#define REG_R9L 9 +#define REG_R10L 10 +#define REG_R11L 11 +#define REG_R12L 12 +#define REG_R13L 13 +#define REG_R14L 14 +#define REG_R15L 15 + +// 16-bit global pointer +#define REG_AX 0 +#define REG_CX 1 +#define REG_DX 2 +#define REG_BX 3 +#define REG_SP 4 +#define REG_BP 5 +#define REG_SI 6 +#define REG_DI 7 +#define REG_R8W 8 +#define REG_R9W 9 +#define REG_R10W 10 +#define REG_R11W 11 +#define REG_R12W 12 +#define REG_R13W 13 +#define REG_R14W 14 +#define REG_R15W 15 + +// 32-bit global pointer +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 +#define REG_R8D 8 +#define REG_R9D 9 +#define REG_R10D 10 +#define REG_R11D 11 +#define REG_R12D 12 +#define REG_R13D 13 +#define REG_R14D 14 +#define REG_R15D 15 + +// 64-bit global pointer +#define REG_RAX 0 +#define REG_RCX 1 +#define REG_RDX 2 +#define REG_RBX 3 +#define REG_RSP 4 +#define REG_RBP 5 +#define REG_RSI 6 +#define REG_RDI 7 +#define REG_R8 8 +#define REG_R9 9 +#define REG_R10 10 +#define REG_R11 11 +#define REG_R12 12 +#define REG_R13 13 +#define REG_R14 14 +#define REG_R15 15 + +#endif @@ -0,0 +1,11 @@ +BITS 64 +section .text + global _start + +_start: + ; 60 = syscall exit + mov eax, ecx + + ; rdi is exit code + mov rdi, 0x41 + syscall diff --git a/write_elf.c b/write_elf.c new file mode 100644 index 0000000..62b6cd3 --- /dev/null +++ b/write_elf.c @@ -0,0 +1,141 @@ +#include "instructions.h" +#include "registers.h" +#include <elf.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +unsigned char some_opcodes[] = {MOVDI(REG_EAX, 0x3c), + // 0xb8, 0x3c, 0x00, 0x00, 0x00, + MOVDI(REG_EDI, 0x41), + // 0xbf, 0x41, 0x00, 0x00, 0x00, + SYSCALL}; +unsigned int some_opcodes_len = sizeof(some_opcodes) / sizeof(some_opcodes[0]); + +int +write_elf(char* restrict file, size_t opcodes_len, char* restrict opcodes) { + int error = 0; + + Elf64_Phdr header_program[] = { + //{ + // .p_type = PT_LOAD, + // .p_flags = PF_R, + // .p_offset = 0, /* Segment file offset */ + // .p_vaddr = 0x400000, /* Segment virtual address */ + // .p_paddr = 0x400000, /* Segment physical address */ + // .p_filesz = 0xb0, /* Segment size in file */ + // .p_memsz = 0xb0, /* Segment size in memory */ + // .p_align = 0x1000, /* Segment alignment */ + //}, + { + .p_type = PT_LOAD, + .p_flags = PF_X | PF_R, + .p_offset = + sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr), /* Segment file offset */ + .p_vaddr = 0x400000 + sizeof(Elf64_Ehdr) + + sizeof(Elf64_Phdr), /* Segment virtual address */ + .p_paddr = 0x400000 + sizeof(Elf64_Ehdr) + + sizeof(Elf64_Phdr), /* Segment physical address */ + .p_filesz = opcodes_len, /* Segment size in file */ + .p_memsz = opcodes_len, /* Segment size in memory */ + .p_align = 0x1, /* Segment alignment */ + }, + }; + + Elf64_Shdr header_section[] = { + { + // .init + // Index in section header string table + .sh_name = 0, + .sh_type = 0, + .sh_flags = 0, + .sh_addr = 0, + .sh_offset = 0, + .sh_size = 0, + .sh_link = 0, + .sh_info = 0, + .sh_addralign = 0, + .sh_entsize = 0, + }, + { + // .init + // Index in section header string table + .sh_name = 0, + .sh_type = SHT_PROGBITS, + .sh_flags = SHF_ALLOC | SHF_EXECINSTR, + .sh_addr = 0x401000, + .sh_offset = 0x1000, + .sh_size = opcodes_len, + /* todo: deps on type */ + .sh_link = 0, + /* todo: deps on type */ + .sh_info = 0, + .sh_addralign = 4, + .sh_entsize = 0, + }, + { + // .shstrtab Section Header String Table + // Index in section header string table + .sh_name = 1, + .sh_type = SHT_STRTAB, + .sh_flags = 0, + .sh_addr = 0x100, + .sh_offset = 0x2000, + .sh_size = opcodes_len, + /* todo: deps on type */ + .sh_link = 0, + /* todo: deps on type */ + .sh_info = 0, + .sh_addralign = 1, + .sh_entsize = 0, + }, + }; + + unsigned char string_header_table[] = {0, '.', 'i', 'n', 'i', 't', 0}; + + Elf64_Ehdr header = { + // memset(&header, 0, sizeof(Elf64_Ehdr)); + .e_ident = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS64, ELFDATA2LSB, + EV_CURRENT, ELFOSABI_SYSV}, + .e_type = ET_EXEC, + .e_machine = EM_X86_64, + .e_version = EV_CURRENT, + .e_entry = 0x400000 + sizeof(Elf64_Ehdr) + + sizeof(Elf64_Phdr), // point to VIRTUAL address of _start + .e_phoff = sizeof(Elf64_Ehdr) /* Program header table offset */, + .e_shoff = 0, // sizeof(Elf64_Ehdr) + sizeof(header_program) /* Section + // header table offset */, + .e_flags = 0, + .e_ehsize = sizeof(Elf64_Ehdr), + .e_phentsize = sizeof(Elf64_Phdr), + // If larger than PN_XNUM, then set to PN_XNUM and store real number in + // sh_info of first program header entry + .e_phnum = 1, + .e_shentsize = sizeof(header_section[0]), + // If larger than SHN_LORESERVE, then set to 0 and store real number in + // sh_size of first section header entry + .e_shnum = 0, // sizeof(header_section) / sizeof(header_section[0]), + // If larger than SHN_LORESERVE, then set to SHN_XINDEX and store real index + // in + // sh_link of first section header entry + .e_shstrndx = 0, + }; + + size_t bytes_written = 0; + FILE* fd = fopen(file, "w"); + + fwrite(&header, sizeof(Elf64_Ehdr), 1, fd); + fwrite(&header_program, sizeof(Elf64_Phdr), + sizeof(header_program) / sizeof(header_program[0]), fd); + // fseek(fd, 0x1000, SEEK_SET); + + do { + bytes_written += fwrite(opcodes, sizeof(char), opcodes_len, fd); + } while (bytes_written != opcodes_len); + error = fclose(fd); + if (error) { + err(EXIT_FAILURE, "no way"); + } + return 0; +} |
