0

I was trying to write an OpenGL/GLFW application with nasm assembly, and I decided to link using gcc since ld was giving me some trouble, but it kept giving me the same error recompile with -fPIE, which I did but that did not change the output in the slightest. This was the error produced:

/usr/bin/ld: Main.o: relocation R_X86_64_32S against `.bss' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status

These are the commands that I have tried:

$ nasm -f elf64 Main.asm

$ gcc -nostartfiles Main.o -lc -glfw -lGL -o Application
$ gcc -nostartfiles Main.o -lc -glfw -lGL -o Application -fPIE
$ gcc -fPIE -nostartfiles Main.o -lc -glfw -lGL -o Application

$ gcc Main.o -o Application -glfw -lGL -lc
$ gcc Main.o -o Application -glfw -lGL -lc -fPIE
$ gcc  -fPIE Main.o -o Application -glfw -lGL -lc

and yes, I have changed _start to main when needed (when I changed assembler)

This is the assembly code if it mattered:

global _start

%define GL_COLOR_BUFFER_BIT 0x00004000
%define GL_TRIANGLES        0x0004

extern glfwInit
extern glfwTerminate
extern glfwCreateWindow
extern glfwDestroyWindow
extern glfwMakeContextCurrent
extern glfwSwapBuffers
extern glfwPollEvents
extern glfwWindowShouldClose

extern glClear
extern glBegin
extern glVertex2f
extern glEnd

section .data
    title: db "OpenGL/ASM", 0x00
section .bss
    window resq 0x1

section .text
_start:
    call glfwInit

    mov rdi, 0x500
    mov rsi, 0x2D0
    mov rdx, title
    mov rcx, 0x00
    mov r8,  0x00
    call glfwCreateWindow
    mov [window], rax

    mov rdi, [window]
    call glfwMakeContextCurrent
gameLoop:
    mov rdi, GL_COLOR_BUFFER_BIT
    call glClear

    mov rdi, GL_TRIANGLES
    call glBegin
    mov rdi, __float32__(-0.5)
    mov rsi, __float32__(-0.5)
    call glVertex2f
    mov rdi, __float32__( 0.5)
    mov rsi, __float32__(-0.5)
    call glVertex2f
    mov rdi, __float32__( 0.0)
    mov rsi, __float32__( 0.5)
    call glVertex2f
    call glEnd

    mov rdi, [window]
    call glfwSwapBuffers
    call glfwPollEvents

    mov rdi, [window]
    call glfwWindowShouldClose
    cmp rax, 0x00
    je gameLoop

exit:
    mov rdi, [window]
    call glfwDestroyWindow
    call glfwTerminate

    mov rax, 0x3C
    mov rdi, 0x00

SOLVED

Thanks to @xiver77, he pointed out that gcc was using relative addressing in this case, that was part of the issue, but also what allowed this to work finally was using the procedural linkage table (using wrt ..plt statements on every C function call). This is the final code

global _start

%define GL_COLOR_BUFFER_BIT 0x00004000
%define GL_TRIANGLES        0x0004

extern glfwInit
extern glfwTerminate
extern glfwCreateWindow
extern glfwDestroyWindow
extern glfwMakeContextCurrent
extern glfwSwapBuffers
extern glfwPollEvents
extern glfwWindowShouldClose

extern glClear
extern glBegin
extern glVertex2f
extern glEnd

section .data
    title: db "OpenGL/ASM", 0x00
section .bss
    window resq 0x1

section .text
_start:
    call glfwInit wrt ..plt

    mov rdi, 0x500
    mov rsi, 0x2D0
    mov rdx, title
    mov rcx, 0x00
    mov r8,  0x00
    call glfwCreateWindow wrt ..plt
    mov [rel window], rax

    mov rdi, [rel window]
    call glfwMakeContextCurrent wrt ..plt
gameLoop:
    mov rdi, GL_COLOR_BUFFER_BIT
    call glClear wrt ..plt

    mov rdi, GL_TRIANGLES
    call glBegin wrt ..plt
    mov rdi, __float32__(-0.5)
    mov rsi, __float32__(-0.5)
    call glVertex2f wrt ..plt
    mov rdi, __float32__( 0.5)
    mov rsi, __float32__(-0.5)
    call glVertex2f wrt ..plt
    mov rdi, __float32__( 0.0)
    mov rsi, __float32__( 0.5)
    call glVertex2f wrt ..plt
    call glEnd wrt ..plt

    mov rdi, [rel window]
    call glfwSwapBuffers wrt ..plt
    call glfwPollEvents wrt ..plt

    mov rdi, [rel window]
    call glfwWindowShouldClose wrt ..plt
    cmp rax, 0x00
    je gameLoop

exit:
    mov rdi, [rel window]
    call glfwDestroyWindow wrt ..plt
    call glfwTerminate wrt ..plt

    mov rax, 0x3C
    mov rdi, 0x00

And to assemble and link:

$ nasm -f elf64 Main.asm
$ gcc -nostartfiles Main.o -o Application -lglfw -lGL -lc -fPIE
$ ./Application
Hachem
  • 1
  • 3
  • 1
    Try `[rel window]`. – xiver77 Jul 24 '22 at 20:10
  • @xiver77 i tried that, but now it gives PIE errors with glfwInit. `relocation R_X86_64_PC32 against symbol 'glfwInit' can not be used when making a PIE object; recompile with -fPIE` – Hachem Jul 24 '22 at 20:13
  • I haven't thought deeply, but generally, you have to be consistent with addressing. It depends on your system whether GCC uses relative or absolute addressing by default. In your case, GCC is configured to do relative addressing, so you have to either match that with `[rel ..]` or make gcc use absolute addressing. BTW what's wrong with using `ld` directly? – xiver77 Jul 24 '22 at 20:30
  • @xiver77 thats true i forget sometimes about absolute/relative addressing in gcc, ill be careful next time. `ld` really just doesnt seem to work at all, the generated binary just seems to not be executable, when i go to run it i just get `no such file or directory: ./Application` – Hachem Jul 24 '22 at 20:34
  • I'm interested how exactly you invoked `ld`, but GCC can also do the job, so that part isn't that important. Is there a reason you typed `-glfw` instead of `-lglfw`? I'm just doing guesswork, but try `gcc Main.o -o Application -lglfw -lGL` with `main` and `[rel ..]`. – xiver77 Jul 24 '22 at 20:39
  • @xiver77 i tried running ld directly on the binary, like so `ld -o Application Main.o -glfw -lGL`, I also tried manually setting the dynamic linker like so: `ld -o Application Main.o --dynamic-linker=/lib64/ld-linux-x86_64.so.2 -lglfw -lGL`, but now its solved, i edited the post to show the solution, thanks a lot of your help! – Hachem Jul 24 '22 at 20:43
  • 1
    It might be easier to just link with `-no-pie` than getting your code PIE compliant. – fuz Jul 24 '22 at 21:21

0 Answers0