Assembler output does not run on my Linux machine

我们两清 提交于 2020-12-13 04:54:00

问题


I followed up this page and compiled the following code

; 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

via

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

none of the executables hp64A and hp64B can run.

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

while both are executables.

$ 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*

My machine is

$ 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

How can I run these executable files?


回答1:


You presumably have the wrong path for the dynamic linker.

Use GCC if you want to make a dynamic executable, especially if you want to link any libraries. Your distro configures it with the right ld.so path and so on. (Use gcc -v to see the right path, and/or ldd ./a.out or readelf to print the ELF interpreter path from a working executable on your system.)

  • gcc main.o links normally, including CRT startup, libc, and libgcc helper functions.

  • gcc -no-pie -nostartfiles start.o omits CRT (so you can write a _start). On Linux this does happen to work; glibc arranges for its init functions to be called via dynamic linker hooks so if you know what you're doing it can work.

    In general if you want to use libc functions, though, write a main that's called by CRT startup code.

    I used -no-pie here because your code uses the mov r32, imm32 optimization for putting static addresses in registers; it depends on the non-PIE default code model. (Otherwise use RIP-relative LEA).

  • gcc -nostdlib omits CRT and standard libs. You can also manually add some libraries onto the GCC command line after that. (If -pie is the default for your GCC, this will still make a PIE even if there are no libraries. static-pie is a separate thing not on by default.)

  • gcc -nostdlib -static makes a plain static ELF executable (implying -no-pie), like you'd get from just ld

If you omit -no-pie from any of these (except with -static) you get a PIE if your GCC was configured with --enable-default-pie like most distros have done for the last couple years. (32-bit absolute addresses no longer allowed in x86-64 Linux?) See also What's the difference between "statically linked" and "not a dynamic executable" from Linux ldd? re: static-pie

Also in a PIE executable, you need to call library functions through the PLT or via their GOT entry, like call [printf wrt.. got]


`int  0x80`

Don't do that for 2 reasons:

  1. legacy 32-bit ABI: What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
  2. Don't use a raw _exit system call after printing with stdio functions. If you pipe the output, stdout will be full-buffered and output will be lost when sys_exit quits without flushing stdio buffers first. Return from main or call sys_exit.


来源:https://stackoverflow.com/questions/58748846/assembler-output-does-not-run-on-my-linux-machine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!