问题
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 themov 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 justld
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:
- legacy 32-bit ABI: What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
- 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 whensys_exit
quits without flushing stdio buffers first. Return frommain
orcall sys_exit
.
来源:https://stackoverflow.com/questions/58748846/assembler-output-does-not-run-on-my-linux-machine