Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help me override _exit in glibc

29 views
Skip to first unread message

Frederick Virchanza Gotham

unread,
Jun 12, 2023, 10:57:20 AM6/12/23
to

When I want to execute some code at the very beginning of my program, I write an assembler function called 'pre_start', and then I do:

g++ -o prog main.cpp my_compiled_assembler.o -e pre_start

This allows me to do a few little things before glibc gets initialised.

What I want to do now though, is that I want to do a few little things after glibc has totally shut down. I thought this would have been as simple as rewriting 'pre_start' as follows:

pre_start:
call __libc_start_main
call __my_little_things_to_do
syscall exit

but it turns out that the function '__libc_start_main' never returns. Internally, it invokes '_exit' which performs a syscall to terminate the process.

So I'm thinking that in order to do something after glibc has shut down, I will have to override _exit so that I can put a line or two of code right before the syscall to exit.

I have written my own separate library which exports '_exit', and then I use LD_PRELOAD at the command line to load this library into my program. This doesn't work though -- glibc is still invoking its own '_exit' instead of mine.

Will it be possible to get the glibc library to invoke my own '_exit' instead of the one that's built into libc.so.6? I want to try pull this off without editing and recompiling the source code for glibc. (Obviously I could edit the glibc source code and mark some symbols as weak, but for now I'm trying to pull this off without editing glibc).

Frederick Virchanza Gotham

unread,
Jun 12, 2023, 7:07:44 PM6/12/23
to
On Monday, June 12, 2023 at 3:57:20 PM UTC+1, Frederick Virchanza Gotham wrote:
>
> So I'm thinking that in order to do something after glibc has shut down,
> I will have to override _exit so that I can put a line or two of code right
> before the syscall to exit.


When my program first starts, before it calls '__libc_start_main', I print out the contents of "/proc/self/status".

And then when my program ends, after all the 'atexit' functions and destructors have been called, I again want to print out the contents of "/proc/self/status".

In order to print the file contents *without* using glibc, I use syscalls in x86_64 assembler.

Here's the x86_64 assembler I've written to print out "/proc/self/status". I'm already able to call this function before jumping into "_start", but I also need to find out some way of calling it right before the "syscall(exit)" is invoked inside '__libc_start_main'. If anyone has any ideas on how to do this then please tell me.

global PrintStatus:function
PrintStatus:
push r15 ; callee-saved - we shall restore later

; On the next 6 lines, I push the string "/proc/self/status"
; onto the stack 8 bytes at a time in Little Endian
mov r15, 0x0000000000000073 ; "s" (with a null terminator)
push r15
mov r15, 0x75746174732f666c ; "lf/statu"
push r15
mov r15, 0x65732f636f72702f ; "/proc/se"
push r15

; On the next 5 lines, I do a 'syscall(read)' to open "/proc/self/status"
mov rax, 2 ; open
mov rdi, rsp ; path
mov rsi, 0 ; flags
mov rdx, 0 ; mode
syscall

; The return value in RAX is the file descriptor, which I will save in r15
mov r15, rax

; If file descriptor is negative then bail out
test r15, r15
js end_of_func

start_loop:
; The next 5 lines read exactly 1 byte from the file
mov rax, 0 ; read
mov rdi, r15 ; fd
mov rsi, rsp ; char *
mov rdx, 1 ; count
syscall
; The next two lines break out of the loop if less than 1 byte was read
cmp rax, 1
jl end_of_func
; The next 5 lines write 1 byte to stdout
mov rax, 1 ; write
mov rdi, 1 ; fd = stdout
mov rsi, rsp ; char const *
mov rdx, 1 ; len
syscall
jmp start_loop
end_of_func:
add rsp, 24 ; take the string "/proc/self/status" back off the stack
pop r15 ; restore the caller's original value of r15
ret

0 new messages