2010-07-14 17 views
21

¿Cómo uso el direccionamiento relativo de RIP en un programa de ensamblaje de Linux para la arquitectura de AMD64? Estoy buscando un ejemplo simple (un programa Hello mundial) que use el modo de direccionamiento relativo AMD64 RIP.¿Cómo usar el direccionamiento relativo de RIP en un programa de ensamblaje de 64 bits?

Por ejemplo, el siguiente programa de montaje de 64 bits que trabajaría con normal (direccionamiento absoluto):

.text 
    .global _start 

_start: 
    mov $0xd, %rdx 

    mov $msg, %rsi 
    pushq $0x1 
    pop %rax 
    mov %rax, %rdi 
    syscall 

    xor %rdi, %rdi 
    pushq $0x3c 
    pop %rax 
    syscall 

.data 
msg: 
    .ascii "Hello world!\n" 

estoy adivinando que el mismo programa usando RIP direccionamiento relativo sería algo como:

.text 
    .global _start 

_start: 
    mov $0xd, %rdx 

    mov msg(%rip), %rsi 
    pushq $0x1 
    pop %rax 
    mov %rax, %rdi 
    syscall 

    xor %rdi, %rdi 
    pushq $0x3c 
    pop %rax 
    syscall 

msg: 
    .ascii "Hello world!\n" 

La versión normal funciona muy bien cuando se compila con:

as -o hello.o hello.s && ld -s -o hello hello.o && ./hello 

Pero no puedo hacer funcionar la versión RIP.

¿Alguna idea?

--- ---- edición

la respuesta de Stephen Canon hace que el trabajo de la versión RIP.

Ahora, cuando desmonte el ejecutable de la versión RIP me sale:

objdump -d hola

0000000000400078 <.text>: 
    400078: 48 c7 c2 0d 00 00 00 mov $0xd,%rdx 
    40007f: 48 8d 35 10 00 00 00 lea 0x10(%rip),%rsi  # 0x400096 
    400086: 6a 01     pushq $0x1 
    400088: 58     pop %rax 
    400089: 48 89 c7    mov %rax,%rdi 
    40008c: 0f 05     syscall 
    40008e: 48 31 ff    xor %rdi,%rdi 
    400091: 6a 3c     pushq $0x3c 
    400093: 58     pop %rax 
    400094: 0f 05     syscall 
    400096: 48     rex.W 
    400097: 65     gs 
    400098: 6c     insb (%dx),%es:(%rdi) 
    400099: 6c     insb (%dx),%es:(%rdi) 
    40009a: 6f     outsl %ds:(%rsi),(%dx) 
    40009b: 20 77 6f    and %dh,0x6f(%rdi) 
    40009e: 72 6c     jb  0x40010c 
    4000a0: 64 21 0a    and %ecx,%fs:(%rdx) 

que muestra lo que estaba tratando de lograr: 0x10 LEA (% RIP), RSI% carga la dirección 17 bytes después de la instrucción lea, que es la dirección 0x400096 donde se puede encontrar la cadena Hello world y, por lo tanto, resulta en un código de posición independiente.

+1

¿Por qué 17 bytes después (0x10 es 16)? – fadedbee

+3

https://www.tortall.net/projects/yasm/manual/html/nasm-effaddr.html dice: 'RIP es el registro de puntero de instrucción, que contiene la dirección de la ubicación inmediatamente después de la instrucción actual' pero' La instrucción lea' tiene siete bytes de longitud, no una. – fadedbee

+0

¿Por qué 'push' /' pop' pares en lugar de 'mov'? –

Respuesta

18

Creo que desea cargar la dirección de su cadena en %rsi; su código intenta cargar una palabra cuádruple desde esa dirección en lugar de la dirección misma. Usted quiere:

lea msg(%rip), %rsi 

si no me equivoco. No tengo una caja de linux para probar, sin embargo.

+0

Sí, eso funciona, ¡muchas gracias! – Erik

+0

@Erik: feliz de ayudar. –

+4

si usa lea msg (% rsp),% rsi en vez de lea msg (% rip),% rsi (o cualquier registro pero no rip) la dirección de la etiqueta mes se agrega no la compensación del actual valor de registro proporcionado. por ejemplo, si msg está en la dirección 0x1FF y luego utiliza lea msg (% rsp),% rsi causa rsi = * (rsp + 0x1FF) no rsi = * ((rsp - 0x1FF) + rsp) como desensamblador dio 0x10 (% rip) porque la distancia desde el desgarre actual y msg es de 0x10 byts. pero no puedo encontrar en los documentos que haya una diferencia en el cálculo entre los registros de extracción y otros registros – user2808671

Cuestiones relacionadas