0

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.

13
  • 1
    How do you expect to fit 32-bit (?) addresses into 16-bit 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 with gcc -no-pie, you'd then run into R_X86_64_16 problems. For the actual question you asked about, duplicate of 32-bit absolute addresses no longer allowed in x86-64 Linux? Commented Apr 20, 2022 at 9:50
  • 1
    Do that and link with gcc -no-pie, you have to fix both parts, that's why I mentioned them both, and said the -no-pie thing 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 .quad instead of dq. Commented Apr 20, 2022 at 10:05
  • 1
    Ok, that's weird. Non-PIE executables are a good way to get stuff working before you understand all the x86-64 details of how to use RIP-relative addressing, but yeah the code you edited into the question is correct if you don't need it to actually be position-independent. (Runtime fixups for 64-bit absolute addresses). Although normally you'd put your jump table in .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 that dq. And also it'll get pulled into L1d as well as L1I) Commented Apr 20, 2022 at 10:19
  • 1
    As for duplicates about x86-64 jump tables, turns out How do you create jump tables in x86/x64? already shows one using RIP-relative LEA. It's MASM syntax, not NASM, though. Commented Apr 20, 2022 at 10:20
  • 1
    So you want this for production use, but you're hand-writing in assembly while you barely know it? I assumed this was just for learning purposes. Or is it a school assignment? If so, I'd recommend that your professor should make the fixed build commands include -fno-pie -no-pie to 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.) Commented Apr 20, 2022 at 10:26

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.