Skip to content

Instantly share code, notes, and snippets.

@ahillo
Last active September 9, 2022 12:59
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahillo/6a1d70b23a97260f6be9 to your computer and use it in GitHub Desktop.
Save ahillo/6a1d70b23a97260f6be9 to your computer and use it in GitHub Desktop.
Using LLVM+MinGW to compile LLVM IR to an exe on Windows, with gdb-compatible debug symbols

Pseudo-C file (03.cpp)

int main(int argc, const char *argv[]) {
	print("hello 123 world");
	print("hello 123 world");
	print("hello 123 world");
	return 0;	
}

LLVM file (03.ll)

; ModuleID = '03.cpp'
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc18.0.0"

@.str = private unnamed_addr constant [17 x i8] c"hello 123 world\0A\00"     ; Declare the string constant as a global constant.

declare i32 @puts(i8* nocapture) nounwind        ; External declaration of the puts function

; Function Attrs: norecurse nounwind
define i32 @main(i32 %argc, i8** %argv) #0 !dbg !4 {
  %1 = alloca i32, align 4
  %2 = alloca i8**, align 4
  %3 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i8** %argv, i8*** %2, align 4
  call void @llvm.dbg.declare(metadata i8*** %2, metadata !15, metadata !16), !dbg !17
  store i32 %argc, i32* %3, align 4
  call void @llvm.dbg.declare(metadata i32* %3, metadata !18, metadata !16), !dbg !19

  %cast210 = getelementptr [17 x i8], [17 x i8]* @.str, i64 0, i64 0

  ; Call puts function to write out the string to stdout.
  call i32 @puts(i8* %cast210), !dbg !20
  call i32 @puts(i8* %cast210), !dbg !21
  call i32 @puts(i8* %cast210), !dbg !22

  ret i32 0, !dbg !23
}

; Function Attrs: nounwind readnone
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1

attributes #0 = { norecurse nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!12, !13}
!llvm.ident = !{!14}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3)
!1 = !DIFile(filename: "03.cpp", directory: "")
!2 = !{}
!3 = !{!4}
!4 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, variables: !2)
!5 = !DISubroutineType(types: !6)
!6 = !{!7, !7, !8}
!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 32, align: 32)
!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 32, align: 32)
!10 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !11)
!11 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
!12 = !{i32 2, !"Dwarf Version", i32 4}
!13 = !{i32 2, !"Debug Info Version", i32 3}
!14 = !{!"clang version 3.9.0 "}
!15 = !DILocalVariable(name: "argv", arg: 2, scope: !4, file: !1, line: 1, type: !8)
!16 = !DIExpression()
!17 = !DILocation(line: 1, column: 32, scope: !4)
!18 = !DILocalVariable(name: "argc", arg: 1, scope: !4, file: !1, line: 1, type: !7)
!19 = !DILocation(line: 1, column: 14, scope: !4)
!20 = !DILocation(line: 2, column: 2, scope: !4)
!21 = !DILocation(line: 3, column: 2, scope: !4)
!22 = !DILocation(line: 4, column: 2, scope: !4)
!23 = !DILocation(line: 5, column: 2, scope: !4)

LLVM "driver" file (toolchain\run.bat)

@echo off

set temp=..\temp\
set in_path=..\
set in_file=03.ll
set out_name=app

cd %0\..\
llvm-as -o %temp%%out_name%.bc %in_path%%in_file%
llc -filetype=obj -O=0 -o %temp%%out_name%.obj %temp%%out_name%.bc
ld %temp%%out_name%.obj -o %temp%%out_name%.exe -lmsvcrt -entry=_main -subsystem=console

cd ..

Step by step

git clone https://github.com/llvm-mirror/llvm
cd llvm
mkdir build
cd build
cmake -G "Visual Studio 12" ..\

start .
  • VS solution LLVM.sln can be found in the opened directory

  • Open the solution and build the following projects:

    • llvm-as
    • llc
  • Copy the output (llvm-as.exe, llc.exe) from llvm\build\release to some_directory\toolchain (we're using "C:\Users______\Desktop\New folder" here.

    • Create run.bat as declared above in some_directory\toolchain
    • Create 03.cpp and 03.ll as declared above in some_directory.
    • Open a terminal, cd to some_directory.
    • Run in terminal
     toolchain\run
     temp\app.exe
     gdb temp\app.exe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment