Вывод ассемблера не запускается на моей машине с Linux - PullRequest
1 голос
/ 07 ноября 2019

Я проследил за этой страницей и скомпилировал следующий код

; assembly program that calls a C function on 64-bit Linux
;
;    int main(void) {
;       printf(fmt, 1, msg1);
;       printf(fmt, 2, msg2);
;       return 0;
;
; Assemble in 64-bit:   nasm  -f elf64 -o hp64.o -l hp64.lst  hello-printf-64.asm
;
; Link:         ld hp64.o  -o hp64  -lc  --dynamic-linker /lib/ld-2.7.so
;   or maybe    ld hp64.o  -o hp64  -lc  --dynamic-linker /lib/ld-linux-x86-64.so.2
;       (the "-lc" option is needed to resolve "printf")
;---------------------------------------
    section .data
fmt     db "%u  %s",10,0
msg1    db "Hello",0
msg2    db "Goodbye",0

    section .text
    extern printf
    global _start

_start:
    mov  edx, msg1
    mov  esi, 1
    mov  edi, fmt
    mov  eax, 0     ; no f.p. args
    call printf

    mov  edx, msg2
    mov  esi, 2
    mov  edi, fmt
    mov  eax, 0     ; no f.p. args
    call printf

    mov  ebx, 0     ; return value
    mov  eax, 1
    int  0x80

через

nasm  -f elf64 -o hp64.o -l hp64.lst  hello-printf-64.asm
ld hp64.o  -o hp64A  -lc  --dynamic-linker /lib/ld-2.7.so
ld hp64.o  -o hp64B  -lc  --dynamic-linker /lib/ld-linux-x86-64.so.2

ни один из исполняемых файлов hp64A и hp64B не можетзапустить.

$ ./hp64A
bash: ./hp64A: No such file or directory
$ ./hp64B
bash: ./hp64B: No such file or directory

, в то время как оба являются исполняемыми файлами.

$ ll
total 30
drwxrwxrwx 1 ar2015 ar2015 4096 Nov  7 23:23 ./
drwxrwxrwx 1 ar2015 ar2015 4096 Nov  7 22:46 ../
-rwxrwxrwx 1 ar2015 ar2015  928 Nov  7 22:47 hello-printf-64.asm*
-rwxrwxrwx 1 ar2015 ar2015 2960 Nov  7 23:21 hp64A*
-rwxrwxrwx 1 ar2015 ar2015 2976 Nov  7 23:21 hp64B*
-rwxrwxrwx 1 ar2015 ar2015 2448 Nov  7 23:21 hp64.lst*
-rwxrwxrwx 1 ar2015 ar2015 1104 Nov  7 23:21 hp64.o*

Моя машина

$ uname -a
Linux ar2015co 4.15.0-66-generic #75~16.04.1-Ubuntu SMP Tue Oct 1 14:01:08 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Как я могу запустить эти исполняемые файлы?

1 Ответ

3 голосов
/ 07 ноября 2019

Возможно, у вас неправильный путь для динамического компоновщика.

Используйте GCC, если вы хотите создать динамический исполняемый файл, особенно если вы хотите связать какие-либо библиотеки . Ваш дистрибутив настраивает его по правильному пути ld.so и так далее. (Используйте gcc -v, чтобы увидеть правильный путь, и / или ldd ./a.out или readelf, чтобы напечатать путь интерпретатора ELF из рабочего исполняемого файла в вашей системе.)

  • gcc main.o обычно связывается, включая запуск CRT, libc и вспомогательные функции libgcc.
  • gcc -no-pie -nostartfiles start.o опускает CRT (поэтому вы можете написать _start). В Linux это действительно работает;glibc организует вызов своих функций init через ловушки динамического компоновщика, поэтому, если вы знаете, что делаете, он может работать.

    В общем, если вы хотите использовать функции libc, напишите main, этовызывается кодом запуска CRT.

    Я использовал -no-pie здесь, потому что ваш код использует оптимизацию mov r32, imm32 для помещения статических адресов в регистры;это зависит от модели кода по умолчанию без PIE. (В противном случае используйте REA-относительный LEA).

  • gcc -nostdlib -no-pie опускает CRT и стандартные библиотеки, но все же может сделать динамический исполняемый файл PIE. После этого вы также можете вручную добавить некоторые библиотеки в командную строку GCC.
  • gcc -nostdlib -static делает простой статический исполняемый файл ELF (подразумевающий -no-pie), как если бы вы получали просто от ld

Если вы опустите -no-pie из любого из них (кроме -static), вы получите PIE, если ваш GCC был настроен на --enable-default-pie, как большинство дистрибутивов сделали за последние пару лет. ( 32-разрядные абсолютные адреса больше не разрешены в x86-64 Linux? )

Также в исполняемом файле PIE вам необходимо вызывать библиотечные функции через PLT или через их GOTзапись , например call [printf wrt.. got]


`int  0x80`

Не делайте этого по 2 причинам:

  1. устаревший 32-разрядный ABI: Что произойдет, если вы используете 32-битный int 0x80 Linux ABI в 64-битном коде?
  2. Не использовать необработанный системный вызов _exit после печати с помощью stdiofunctions. Если вы передадите вывод, stdout будет полностью буферизован, и выход будет потерян, когда sys_exit завершит работу без предварительной очистки буферов stdio. Возврат из main или call sys_exit.
...