The problem is that you're overwriting the saved frame (base) pointer with nonsense, which means secret can't find its return address. When a function in a typical x86/64 C runtime is called, two values typically get pushed onto the stack (not counting any parameters): the return address (this is the start of the instruction following the call, and is done automatically by the call instruction), and then the calling function's base pointer (also called "frame pointer" because it points to the function's stack frame), stored in register ebp; this is done in the first operation of the function's prologue). The next operation in the prologue stores the current value of the stack pointer (register esp) into the base pointer (ebp) so it points at the base of the new frame, and then the third operation creates the new stack frame by subtracting the relevant range from the stack pointer (remember, the stack grows from high addresses toward low ones).
When a function returns, these operations happen in reverse order. First the base pointer is stored into the stack pointer (moving the stack pointer back up to where it was immediately after the old base pointer was saved, before the initial stack allocation and any other stack allocations that might have happened during the function). Then the (current) top value of the stack - the saved base pointer - gets popped into ebp, restoring the caller's base pointer value (and meaning that esp now points just below the return address). Then the ret instruction pops the instruction pointer (register eip) off the stack to the return address.
Currently, your stack and execution path before the exploit looks like this (in address order, so the tip is at the bottom):
return address for C runtime function that calls main
saved base pointer for C runtime function that calls main
<anything that main put on the stack other than saved base pointer but before calling reading>
return addr to main right after the call to reading
saved base pointer for main
buffer "buf"
but after the exploit you've modified what was the return address to main, and in the process smashed the saved base pointer for main. Because secret doesn't use the stack for anything when it's running, you can even skip its prologue if you want to (which saves you from trying to manipulate memory at the fake address currently stored in esp). However, when secret tries to return, it's going to set esp to address 0xAAAAAAAA (add more "A"s if 64-bit) and then try and pop the saved base pointer (and then the return address) from there, which is not going to work.
What you want to do here is preserve the return address (into the middle of main) as the return address that secret finds when returning. The simple option is to extend your current stack smash into part of main's stack, adding the correct return address into main as the next pointer down the stack (which is likely going to overwrite main's own saved base pointer, but that's OK, because this main never returns; it instead calls exit(0) and therefore its epilogue will never see the trashed stack). Obviously you still need to make reading's return address point at secret, but critically, you also need to preserve the value of reading's saved base pointer! That way, when reading "returns", it'll be pointing at the prologue of secret with esp just past the return address into main and ebp pointing at the base of mains stack frame, exactly as if main had called secret instead of reading. Then secret runs, creating its own stack frame, calling printf and returning therefrom, and returns to main correctly. If main tried to return it would find a corrupted stack, but it doesn't.
That's probably sufficient for this problem, but what if you wanted main to return normally? You've trashed the saved base pointer for the C runtime function that calls main, so the epilogue of main would put an address in the middle of main into ebp. That's actually OK if the function below main never needs to use the base pointer for anything (accessing local variables, or restoring its stack pointer to return to a caller two levels below main), e.g. because as soon as main returns, the function that calls it kills the process. But maybe it doesn't; maybe there's multiple functions below main, and the stack needs to unwind, and when main returns, the function below can't find its stack frame and everything goes to hell?
There's another option, which is creating a fake stack frame. You have room in buf to create this fake; you only need room for two pointers, which even on x64 would mean you need just 16 bytes. Instead of filling buf with As, you'll need to fill it with the fake stack frame. Specifically, first put in the return address for main (the value from the location you're overwriting with secret's address), then the saved base pointer for main (which currently you overwrite with "A"s). Then when you actually overwrite the saved base pointer, point it at this fake stack frame you've made within buf (and, as you do currently, make the return address point at secret, but skipping the prologue).
In this case, when reading "returns", its epilogue will set (in sequence) esp to the value of ebp (pointing to just past the smashed frame pointer), then ebp will be popped (setting it to point at your fake stack frame, and making esp point at your smashed return address), and then eip will be popped (jumping into the post-prologue body of secret). At this point, esp will still be pointing to the tip of main's stack (where it was right before calling reading), which is a little awkward when you're instead in secret, but that's OK. Because you skipped the prologue, secret doesn't touch the stack until it calls printf, at which point it will overwrite the stack locations that were originally used by reading; it'll write the return address into secret the same place main did, then printf will save secret's base pointer (to the fake stack frame) where reading originally saved main's base pointer, and set ebp to the current location of esp (which is the base of what was reading's stack frame). Then printf might do some other stuff, which will hopefully not trample our fake stack frame (that's a risk though, because it's within what is now printf's stack frame)! (Ideally we'd have some more margin here, but the buffer doesn't give us much room).
When printf returns, we'll be again back in secret, with esp again pointing at the tip of main's stack, but ebp pointing at the fake stack frame. When secret returns, it'll unwind that fake stack frame, correctly restoring ebp to the base of main's stack frame, and eip to the next instruction in main (which is the setup for the call printf("Input done\n")). At this point esp will still be pointing at the start of what was once buf, but who cares; that's a perfectly valid place for printf to create its stack frame, and when main returns, its epilogue will restore esp to the tip of the prior function's stack. At this point, all will be right in the stack (assuming the fake frame was set up and pointed to correctly, and not trampled before use), and the program will exit cleanly as it normally does when main finishes without calling exit.
../sysdeps/nptl/libc_start_call_main.h: No such file or directoryis coming from your debugger, not from the program. It means that you're stopped somewhere insidelibc_start_call_main- possibly because you returned from main and subsequently crashed somewhere in the libc function that calls main.