I am writing a project in x86-64 Assembly and I want to write an efficient switch statement using a branch lookup table. However, I get position independence errors.
I'll start with my code. The assembly was taken from this answer.
Assembly:
global mySwitch section .text mySwitch: jmp [.jump_table + 2 * edi] .jump_table: dw .one, .two .one: mov eax, 123 ret .two: mov eax, 321 ret C:
#include <stdio.h> int mySwitch(int arg); int main() { printf("%d\n", mySwitch(1)); } I am trying to compile it with the following commands:
nasm -f elf64 -w+all -w+error switch.asm -o switch_asm.o gcc -c -Wall -Wextra -std=c17 -O2 switch.c -o switch_c.o gcc switch_asm.o switch_c.o -o switch but the third one returns the following error:
/usr/bin/ld: switch_asm.o: relocation R_X86_64_32 against `.text' can not be used when making a PIE object; recompile with -fPIE collect2: error: ld returned 1 exit status make: *** [makefile:4: all] Error 1 Using the -fPIE switch is against the rules of the assignment (and also does not help), and I do not know what I am missing (previously, the problem was caused by a missing rel or wrt ..plt).
Update: Changing my assembly code slightly to 64-bit addresses and a lea instruction like so:
lea rax, [rel .jump_table] jmp [rax + rdi * 8] .jump_table: dq .one, .two compiles, and works as expected. I'd love to post this is an answer as to how to write a switch statement in asm but I cannot because this question is closed due to being a duplicate despite not being a duplicate so oh well.
dw(data words)? The Q&A you're copying from is 16-bit code, and you only changed the addressing-mode to be 32-bit instead of 64-bit when porting to x86-64, which is weird. Even if you did link a non-PIE executable withgcc -no-pie, you'd then run intoR_X86_64_16problems. For the actual question you asked about, duplicate of 32-bit absolute addresses no longer allowed in x86-64 Linux?gcc -no-pie, you have to fix both parts, that's why I mentioned them both, and said the-no-piething was the solution to the first error, the on you mention in the title. See also How to remove "noise" from GCC/clang assembly output? for how to look at compiler output for examples, although that will use GAS syntax instead of NASM. But GAS .intel_syntax is similar except for directives like.quadinstead ofdq..rodata, not inline with the code where it can create a performance problem (since the default path for branch prediction of an indirect jump is fall-through, into thatdq. And also it'll get pulled into L1d as well as L1I)-fno-pie -no-pieto make x86-64 asm somewhat more beginner-friendly until the details / limitations of RIP-relative addressing have been covered. (feel free to link them my comment here.)