2
votes

The address of str is stored the stack(can use pop to fetch it, and it's position independent):

.text
    str:
        .string "test\n"

But now the address of str is not in the stack(can't use pop to fetch it, but str(%rip)(RIP relative addressing) is PIC):

.text
    str:
        .skip 64

This is what I found from my previous question,

but I don't understand how assembler decides address of str should be in the stack or not?

WHen should I use RIP-relative addressing ,or use pop to make it PIC?

UPDATE

This is working:

.text
    call start
    str:
        .string "test\n"
    start:
    movq    $1, %rax
    movq    $1, %rdi
    popq     %rsi
    movq    $5, %rdx
    syscall
    ret

But if I change popq %rsi to lea str(%rip),%rsi,it wlll cause segmentation fault...

1
The assembler can't put anything on the stack, because the stack isn't created until runtime. Nothing is on the stack unless you put it there.ughoavgfhw
@Je Rog: In both cases str is located in the text segment along with the code for the functions - pop will not retrieve anything. Are you asking about the difference between absolute and relative addressing modes, because then wikipedia has a decent discussion?user786653
@user786653 , why this works if the address is not stored on stack? Pay attention to popq %rsi. pastebin.com/tZ81FvZKJe Rog
Because you put the address on the stack with the call instruction. call pushes the address of the following instruction (in this case your string) onto the stack and jumps to the target address.user786653
@user786653 ,but why it doesn't work if I replace popq %rsi with mov str(%rip), %rsi?Segmentation fault will happen...Je Rog

1 Answers

1
votes

Just to be completely clear: the CALL instruction pushes the address of the instruction following it onto the stack and jumps to the target address. This means that

x: call start 
y: 

is morally equivalent to (ignoring that we trash %rax here):

x: lea y(%rip), %rax
   push %rax
   jmp start 
y: 

Conversely RET pops an address from the stack and jumps to it.

Now in your code you do popq %rsi and then later ret jumps back to whatever called you. If you just change the popq to lea str(%rip), %rsi to load %rsi with the address of str you still have the return value (address of str) on the stack! To fix your code simply manually pop the return value off the stack (add $8, %rsp) OR more sanely move str to after the function so you don't need the awkward call.

Updated with complete stand alone example:

# p.s
#
# Compile using:
# gcc -c -fPIC -o p.o p.s
# gcc -fPIC -nostdlib -o p -Wl,-estart p.o

.text
.global start # So we can use it as an entry point
start:
    movq $1, %rax #sys_write
    movq $1, %rdi
    lea str(%rip), %rsi
    movq $5, %rdx
    syscall

    mov $60, %rax #sys_exit
    mov $0, %rdi
    syscall

.data
str:
    .string "test\n"

Disassembling the code with objdump -d p reveals that the code is indeed position independent, even when using .data.

p:     file format elf64-x86-64
Disassembly of section .text:
000000000040010c <start>:
  40010c:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
  400113:   48 c7 c7 01 00 00 00    mov    $0x1,%rdi
  40011a:   48 8d 35 1b 00 20 00    lea    0x20001b(%rip),%rsi        # 60013c <str>
  400121:   48 c7 c2 05 00 00 00    mov    $0x5,%rdx
  400128:   0f 05                   syscall 
  40012a:   48 c7 c0 3c 00 00 00    mov    $0x3c,%rax
  400131:   48 c7 c7 00 00 00 00    mov    $0x0,%rdi
  400138:   0f 05                   syscall