On Tue, Mar 7, 2023 at 1:05 PM Xi Ruoyao wrote: > > > > (2) Is there any way to stop the GNU linker from putting an undefined > > function in R_X86_64_GLOB_DAT? > > No, unless you avoid extracting its address. I've been doing some major tinkering today. The entry point of an executable is '_start'. So, first I wrote a new entry point in x64 assembler that could differentiate between GUI mode and console mode depending upon the value of 'argc': ; This file contains x86_64 assembler for NASM, also known as x64. ; This file contains two functions: ; static void print8bytes(uint64_t eight_chars,uint64_t new_line); ; extern void pre_start(int argc); section .text print8bytes: ; This is a function that returns void ; Two parameters: ; r9: The 8-byte string to print ; r8: If true, prints a trailing new line ; save all the register values we're going to use push rax push rsi push rdi push rdx ;zero out the registers we are going to need xor rax, rax xor rsi, rsi xor rdi, rdi xor rdx, rdx ;write(int fd, char *msg, unsigned int len) mov al, 1 add di, 1 mov rsi, r9 push rsi mov rsi, rsp mov dl, 8 ; Print 8 bytes at a time syscall pop rsi cmp r8, 1 ; check if r8 is true or false jl no_new_line ;zero out the registers we are going to need xor rax, rax xor rsi, rsi xor rdi, rdi xor rdx, rdx ;write(int fd, char *msg, unsigned int len) mov al, 1 add di, 1 mov rsi, 0x000000000000000a ; new line push rsi mov rsi, rsp mov dl, 1 ; Print just one byte syscall pop rsi no_new_line: ; just a jump label - not a function name pop rdx pop rdi pop rsi pop rax ret global pre_start:function pre_start: ; The 'argc' argument to 'main' is on the top of the stack so ; we will use the frame pointer 'rbp' to keep track of it. push rbp mov rbp, rsp push r9 ; save because we'll use it - pop it back later push r8 ; save because we'll use it - pop it back later mov r8, 0 ; false = don't put trailing new line mov r9, 0x3d3d3d3d3d3d3d3d ; "========" call print8bytes call print8bytes call print8bytes mov r9, 0x6174735f65727020 ; " pre_sta" call print8bytes cmp qword[rbp+8], 2 ; check if argc < 2 jl $+2+10+2 ; if argc < 2 then we want GUI mode mov r9, 0x646d63202d207472 ; "rt - cmd" jmp $+2+10 ; skip the next 10-byte instruction mov r9, 0x495547202d207472 ; "rt - GUI" call print8bytes mov r9, 0x3d3d3d3d3d3d3d3d ; "========" call print8bytes call print8bytes mov r8, 1 ; true = put trailing new line call print8bytes pop r8 pop r9 mov rsp, rbp pop rbp extern _start jmp _start If you see the last line there, I jump straight into _start. So then I build my program with a new entry point as follows: g++ -o prog prog.cpp object_file_from_assembler.o -e pre_start When I run it at the command line, the first thing I get is: ======================== pre_start - GUI======================== and then it continues execution as normal. No problems. So then the next thing I did was I used 'patchelf' to remove the NEEDED for the graphical user interface library: patchelf --remove-needed libgtk-3.so.0 ./prog And then I tried to run it again, but this time around I got back: ./ssh: symbol lookup error: ./ssh: undefined symbol: gtk_true This means that the program falls over ***before*** the entry point is reached. So the part of the Linux operating system that loads executable files is not even going into the entry point for my program, it's falling over before then. I need to stop this happening some how. Perhaps I can put dummy values in the GOT table so that the loader doesn't think they're null? On Tue, Mar 7, 2023 at 1:25 PM Alexander Monakov <amonakov@xxxxxxxxx> wrote: > > > On Tue, 7 Mar 2023, Xi Ruoyao via Gcc-help wrote: > > > This won't work for a function pointer either: the value of the > > function pointer must be the address of foo itself, not foo@plt. Or the > > result of &foo in the shared library and the main executable will be > > different, violating the C or C++ standard. Then we must use > > R_X86_64_JUMP_SLOT which is handled by the dynamic linker. > > (you probably meant GLOB_DAT in the last statement) > > This paragraph is inaccurate: traditional non-PIC, non-PIE codegen uses > direct symbol references. So, when you have a direct reference to foo > in non-PIC main executable, the reference is resolved to its PLT slot, > and the address of that PLT slot becomes the canonical address of 'foo' > for the whole program. > > When the main executable is PIE, it may or may not have a PLT slot for > 'foo', and if it doesn't, the canonical address of 'foo' is its actual > implementation. > > Alexander