Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

malloc and strcpy in LLVM #235

Closed
ghost opened this issue Mar 12, 2024 · 1 comment
Closed

malloc and strcpy in LLVM #235

ghost opened this issue Mar 12, 2024 · 1 comment
Labels

Comments

@ghost
Copy link

ghost commented Mar 12, 2024

Hi everyone,

I'm still discovering LLIR/LLVM. I need to support global string variables in my target language. My goal is:

  • define a global point to string
  • allocate a block of memory with malloc
  • copy a string constant in the allocated block
  • copy the address of the block to the global variable
  • ... // in real word, do something else
  • get memory address from global variable
  • free memory

So I wrote the following prototype code the implement this:

func TestStrAllocGEN(*testing.T) {
	// Create a new LLVM IR module.
	m := ir.NewModule()
	// Convenience types and values.
	i32 := types.I32
	i8 := types.I8
	i8ptr := types.NewPointer(i8)

	// create link to stdlib.h
	// add string functions
	strcpy := m.NewFunc("strcpy", i8ptr, ir.NewParam("dst", i8ptr), ir.NewParam("src", i8ptr))
	puts := m.NewFunc("puts", i32, ir.NewParam("s", i8ptr))

	// memory management
	malloc := m.NewFunc("malloc", i8ptr, ir.NewParam("size", types.I32))
	free := m.NewFunc("free", types.Void, ir.NewParam("ptr", i8ptr))

	// Create a global variable of type string.
	str := m.NewGlobal("str", i8ptr)
	str.Init = constant.NewNull(i8ptr)

	// Create a new function main which returns an i32.
	main := m.NewFunc("main", types.I32)
	entry := main.NewBlock("")

	// create temporary string
	str0 := constant.NewCharArrayFromString("Hello, World!\n\x00")
	length := int64(len(str0.X))
	// allocate memory on heap
	str1 := entry.NewCall(malloc, constant.NewInt(types.I32, length))
	// copy string to allocated memory
	// gep := constant.NewGetElementPtr(str0.Typ, str0, zero, zero)
	entry.NewCall(strcpy, str1, str0)
	// store pointer to global string
	entry.NewStore(str1, str)

	// capture the pointer to the string
	str2 := entry.NewLoad(i8ptr, str)
	// call puts
	entry.NewCall(puts, str2) // verify we have the proper content

	// free memory
	entry.NewCall(free, str2)

	// Return 0 from main.
	entry.NewRet(constant.NewInt(types.I32, 0))
	fmt.Println(m)
}

This generated this LLVM:

@str = global i8* null

declare i8* @strcpy(i8* %dst, i8* %src)

declare i32 @puts(i8* %s)

declare i8* @malloc(i32 %size)

declare void @free(i8* %ptr)

define i32 @main() {
0:
	%1 = call i8* @malloc(i32 15)
    
	%2 = call i8* @strcpy(i8* %1, [15 x i8] c"Hello, World!\0A\00"). ; <-- error is here
	store i8* %1, i8** @str. ; <<-- from here and below, not tested yet!
	%3 = load i8*, i8** @str
	%4 = call i32 @puts(i8* %3)
	call void @free(i8* %1)
	ret i32 0
}

I get a segmentation fault error in the strcpy call. Could you help me figuring out what is wrong? Thank you in advance for your precious time.

@ghost
Copy link
Author

ghost commented Mar 12, 2024

Here is my own solution (Thanks to C and clang).

for those interested, here is the revised code:

func TestStrAllocGEN(*testing.T) {
	// Create a new LLVM IR module.
	m := ir.NewModule()
	// Convenience types and values.
	i32 := types.I32
	i8 := types.I8
	i8ptr := types.NewPointer(i8)

	// create link to stdlib.h
	// add string functions
	strcpy := m.NewFunc("strcpy", i8ptr, ir.NewParam("dst", i8ptr), ir.NewParam("src", i8ptr))
	puts := m.NewFunc("puts", i32, ir.NewParam("s", i8ptr))

	// memory management
	malloc := m.NewFunc("malloc", i8ptr, ir.NewParam("size", types.I32))
	free := m.NewFunc("free", types.Void, ir.NewParam("ptr", i8ptr))

	// Create a global variable of type string.
	str := m.NewGlobal("str", i8ptr)
	str.Init = constant.NewNull(i8ptr)

	// test constant
	constantStr0 := constant.NewCharArrayFromString("Hello, World!\n\x00")
	constantStr1 := m.NewGlobalDef(".str0", constantStr0)

	// ---------------------------------------------------------
	// main ()
	// ---------------------------------------------------------
	// Create a new function main which returns an i32.
	main := m.NewFunc("main", types.I32)
	entry := main.NewBlock("")

	length := int64(len(constantStr0.X))
	// allocate heap memory for global strings
	str2 := entry.NewCall(malloc, constant.NewInt(types.I32, length))
	entry.NewStore(str2, str)

	// copy string to allocated memory
	str3 := entry.NewLoad(i8ptr, str)
	entry.NewCall(strcpy, str3, constantStr1)

	// capture the pointer to the string
	str10 := entry.NewLoad(i8ptr, str)
	// call puts
	entry.NewCall(puts, str10)

	// free memory
	entry.NewCall(free, str10)

	// Return 0 from main.
	entry.NewRet(constant.NewInt(types.I32, 0))
	fmt.Println(m)
}

And the resulting LLVM:

@str = global i8* null
@.str0 = global [15 x i8] c"Hello, World!\0A\00"

declare i8* @strcpy(i8* %dst, i8* %src)

declare i32 @puts(i8* %s)

declare i8* @malloc(i32 %size)

declare void @free(i8* %ptr)

define i32 @main() {
0:
        %1 = call i8* @malloc(i32 15)
        store i8* %1, i8** @str
        %2 = load i8*, i8** @str
        %3 = call i8* @strcpy(i8* %2, [15 x i8]* @.str0)
        %4 = load i8*, i8** @str
        %5 = call i32 @puts(i8* %4)
        call void @free(i8* %4)
        ret i32 0
}

@ghost ghost closed this as completed Mar 12, 2024
@mewmew mewmew added the howto label Mar 13, 2024
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant