2

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...

Je Rog
  • 5,675
  • 8
  • 39
  • 47
  • 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 Aug 25 '11 at 17:55
  • @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](http://en.wikipedia.org/wiki/Addressing_mode) has a decent discussion? – user786653 Aug 26 '11 at 15:36
  • @user786653 , why this works if the address is not stored on stack? Pay attention to `popq %rsi`. http://pastebin.com/tZ81FvZK – Je Rog Aug 26 '11 at 15:42
  • 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 Aug 26 '11 at 15:51
  • @user786653 ,but why it doesn't work if I replace `popq %rsi` with `mov str(%rip), %rsi`?Segmentation fault will happen... – Je Rog Aug 26 '11 at 15:56
  • Please edit your question with the complete code that's working and the code that's not working, but it looks like you want to do `lea str(%rip), %rsi` to load `%rsi` with the address of `str` rather than load a quad word from the first 8 bytes of `str` as that instruction does. – user786653 Aug 26 '11 at 16:06

1 Answers1

1

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 
user786653
  • 29,780
  • 4
  • 43
  • 53
  • Is it true assembly with `.data xxx` will NEVER be PIC? And it's still causing segfault when run as `gcc -nostdlib file.s -ggdb -o x;./x`, what's the caller of `x` when built without stdlib? – Je Rog Aug 26 '11 at 16:46
  • @Je Rog: No you just have to remember to use RIP-relative addressing (and possibly `-fPIC` on the command line, depends on what you're trying to achieve). And yes the code will segfault if you just run it like that (but so would yours in the question), I was assuming you were still using the loader from your previous question. If you want it to work stand-alone you need to use sys_exit (60) to end the program, there is nothing to return to. (`mov $60, %rax` `mov $0,%rdi` `syscall`). – user786653 Aug 26 '11 at 17:00
  • I just tried adding `.data` before `str`,and it's not working even if I compile with `-fPIC`.. – Je Rog Aug 26 '11 at 17:11
  • Run it with the loader, run as stand-alone can't prove it's PIC,right? Theoratically it can't be PIC since text and data are stored in different(non-consecutive) positions ... – Je Rog Aug 26 '11 at 17:28
  • @Je Rog: The ELF format (or a.out on ancient platforms) handles that. If you have special requirements as you do you need a link script. You have to be upfront with *all* of the requirements. See [this](http://stackoverflow.com/questions/6828631/plain-binaries-with-gnu-assembler/6829145#6829145) post. You *possibly* want something like this: `ld --oformat binary -pie -e start -Ttext=0x0000 -Tdata=0x1000 -o p.bin p.o` – user786653 Aug 26 '11 at 17:42
  • But it's actually not working if I add `.data` before `str`, I tested it in the loader;And it works if I remove `.data`. – Je Rog Aug 26 '11 at 17:56
  • Again, it's impossible to guess what you're doing/trying, you have to be extremely clear what you're trying to do/have tried. In this case, what *exactly* are you using with your loader (and what is the source code of it), how are you compiling and linking the different parts? Did you try my latest suggestion? If yes, what part isn't working, did you debug? – user786653 Aug 26 '11 at 18:01
  • I'm running it this way: `gcc -c -fPIC write.S -o write.o;objcopy -O binary write.o write.bin;./loader write.bin`,the loader is the same as in the previous post.. – Je Rog Aug 26 '11 at 18:42
  • So you didn't try what I suggested? Rather than use `objcopy` (which you haven't mentioned using before) try doing `ld .... -o write.bin write.o` with the `...` part copied from my previous answer. – user786653 Aug 26 '11 at 18:50
  • I tried,but after that it can neither be run as stand-alone(`cannot execute binary file`) nor run by the loader(`Segmentation fault`) – Je Rog Aug 27 '11 at 00:44
  • Then you're doing it wrong. http://pastebin.com/PGZERsDR `make && ./p && ./run p.bin`. Open a new question WITH ALL THE AVAILABLE INFORMATION AND CODE if you're still having trouble. Perhaps someone else can explain things better for you... – user786653 Aug 27 '11 at 08:59
  • Why do you specify `-Ttext=0x0000 -Tdata=0x100`? It seems this is making the address fixed,and not PIC .. And I tried `make run;./run p`,it reports `Segmentation fault` – Je Rog Aug 27 '11 at 14:36
  • That's where they will be located *in the file*. `p` is an ELF file with headers and so forth that you can't expect to be able to just jump to. – user786653 Aug 28 '11 at 07:46