Сборка ПИК - PullRequest
       17

Сборка ПИК

2 голосов
/ 25 августа 2011

Адрес str хранится в стеке (можно использовать pop для его извлечения, и он не зависит от позиции):

.text
    str:
        .string "test\n"

Но теперь адрес str отсутствует встек (не могу использовать pop для его извлечения, но str(%rip) (относительная адресация RIP) - это PIC):

.text
    str:
        .skip 64

Это то, что я нашел из моего предыдущего вопроса,

но я не понимаю, как ассемблер решает, что адрес str должен быть в стеке или нет?

Когда я должен использовать относительную RIP-адресацию или использовать pop, чтобы сделать его PIC?

ОБНОВЛЕНИЕ

Это работает:

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

Но если я изменю popq %rsi на lea str(%rip),%rsi, это вызовет ошибку сегментации ...

1 Ответ

1 голос
/ 26 августа 2011

Просто для полной ясности: инструкция CALL помещает адрес следующей за ней инструкции в стек и переходит на целевой адрес. Это означает, что

x: call start 
y: 

морально эквивалентно (игнорируя то, что мы хвалим %rax здесь):

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

И наоборот RET извлекает адрес из стека и переходит к нему.

Теперь в своем коде вы делаете popq %rsi, а затем ret возвращается к тому, что вас называло. Если вы просто измените popq на lea str(%rip), %rsi, чтобы загрузить %rsi с адресом str, у вас все еще будет возвращаемое значение (адрес str) в стеке! Чтобы исправить свой код, просто вручную извлеките возвращаемое значение из стека (add $8, %rsp) ИЛИ более разумно переместитесь на str после функции, чтобы вам не нужен неуклюжий вызов.

Обновлено с полным автономным примером:

# 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"

Разборка кода с помощью objdump -d p показывает, что код действительно не зависит от позиции, даже при использовании .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 
...