Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

How are threads created in Linux x86_64

Posted on Sep 23 So I was trying to use atomics in C. Got a little working example.And, I got results like thisGreat! But how is a thread actually spawned? We currently don't know many things, but we know something; threads are created by the OS.As you may know, a Program can do a lot of things by itself. It can add numbers, pass values around functions, compute digits of pi, etc. But it can't print out something to the screen. That's the kernel's job.Well, a program can print out something to the screen, after all the Linux kernel is a bunch of instructions for the CPU to execute. It just has a lot of privileges. It can turn on and off your USB ports and communicate with your NIC and turn on specific pixels on your screen in order to print "Hello, World!".So how does a normal program, an userland program, how does it prints something to the screen. Well, let's figure it out writing a x86_64 Linux assembly "Hello, World" program!We're gonna be using NASM because I don't want to deal with GAS.And then compile it!You can see the syscall instruction there. It basically says to the OS "make this for me, thx". We use it for writing to stdout and exiting the program. So, whenever the program can't do something by itself, say opening a TCP Socket, it asks the OS for it. That's how threads are created! But how to know which syscall does it uses?The man page for strace says "[...] It intercepts and records the system calls which are called by a process and the signals which are received by a process." So this is the tool we need.So let's run it against our new program!As you can see, it shows us which syscalls were called. execve is the syscall that actually runs the program! It is called by our shell, and, in fact, the second argument is equivalent to argv in a C main Function, and the third to envp.Then we can see the other 2 syscalls we invoked, write and exit.So let's dive in and directly strace our program!And it goes like this for 99 lines.So yeah, let's start for something simpler. What about a program that does nothing? And I will make it without a file for the flex!Much better! 65 lines less! It does a bunch of syscalls even when we are doing nothing, so we will chop the lines that seem similar.And if you close your eyes, in our multithread program you can notice the clone3 call being invoked multiple times. Let's check how many times.The same number of threads we create, great!So it seems that clone3 is the syscall that creates new threads. Let's use man (better if you use batman) to find about it.The man page is quite large. It gives us information about the glibc wrapper, clone and about the syscall itself. Let's check the signature of clone.The man page says "When the child process is created with the clone() wrapper function, it commences execution by calling the function pointed to by the argument fn. [...] When the fn(arg) function returns, the child process terminates".It also says something really important about the stack: "The stack argument specifies the location of the stack used by the child process. Since the child and calling process may share memory, it is not possible for the child process to execute in the same stack as the calling process. The calling process must therefore set up memory space for the child stack and pass a pointer to this space to clone()".The stack is basically memory. That's about it. And it's needed for functions to work, because the return address, that is, the address that you should jump to give control back to the caller function, is pushed into the stack. Also you can use it to store local variables and pass more than 6 arguments to functions.So we just need to pass around values and we have it!But how is the function I pass to it executed? I don't see any func_ptr field in clone3 (the syscall)!Well, clone (the function) has a function pointer argument, let's check what it does.The source code for that is here. Surprisingly, it is somewhat well commented! First some sanity checks, then an ABI compliance thing, moving around some stuff to make the syscall, storing the start function and its argument in the stack and when everything is ready, the syscall is made. And with this, the two threads are in the exact same position. The only differences are the stack pointer (in the child thread is the stack we passed to it) and the rax register. In the parent thread, the rax register gets the value the thread ID.In the child thread, it gets to 0. With this logic, we do a little branching and it just works.Unfortunately, this process isn't as easy to visualize without doing it inside a debugger. But eventually, it calls the function that you passed to it. And then it just exits with the value you returned from the thread. The repo is here: https://github.com/beto-bit/mt_asmAside from not using the standard library, it wasn't actually that hard. The glibc implementation is much more complex, but this a (somewhat) working implementation.Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well Confirm For further actions, you may consider blocking this person and/or reporting abuse Toby Chui - May 12 Yofre Ormaza - May 10 Ray Harris - May 10 Fabian Reinders - May 7 Once suspended, betobit will not be able to comment or publish posts until their suspension is removed. Once unsuspended, betobit will be able to comment and publish posts again. Once unpublished, all posts by betobit will become hidden and only accessible to themselves. If betobit is not suspended, they can still re-publish their posts from their dashboard. Note: Once unpublished, this post will become invisible to the public and only accessible to beto-bit. They can still re-publish the post if they are not suspended. Thanks for keeping DEV Community safe. Here is what you can do to flag betobit: betobit consistently posts content that violates DEV Community's code of conduct because it is harassing, offensive or spammy. Unflagging betobit will restore default visibility to their posts. DEV Community — A constructive and inclusive social network for software developers. With you every step of your journey. Built on Forem — the open source software that powers DEV and other inclusive communities.Made with love and Ruby on Rails. DEV Community © 2016 - 2023. We're a place where coders share, stay up-to-date and grow their careers.



This post first appeared on VedVyas Articles, please read the originial post: here

Share the post

How are threads created in Linux x86_64

×

Subscribe to Vedvyas Articles

Get updates delivered right to your inbox!

Thank you for your subscription

×