第一次来到这里,我正在运行Kali linux 64bits,我是一个Linux新手和一个新的ASM以及....所以我在C中拉了一个代码,这完全没问题.....这里是代码:
#include<stdio.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
int main(int argc , char *argv[])
{
int socket_desc;
struct sockaddr_in server;
char *message , server_reply[2000];
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 2000 );
//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) <0)
{
puts("connect error");
return 1;
}
puts("Connected\n");
//Send some data
message = "Hola!!!!\n\r\n";
if( send(socket_desc , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
puts("Data Send\n");
//Receive a reply from the server
if( recv(socket_desc, server_reply , 2000 , 0) < 0)
{
puts("recv failed");
}
puts("Reply received\n");
puts(server_reply);
return 0;
}
所以...我使用gcc -S -o example.s example.c来获取ASM代码......这是:
.file "test.c"
.section .rodata
.LC0:
.string "Could not create socket"
.LC1:
.string "127.0.0.1"
.LC2:
.string "connect error"
.LC3:
.string "Connected\n"
.align 8
.LC4:
.string "Hola!! , \n\r\n"
.LC5:
.string "Send failed"
.LC6:
.string "Data Send\n"
.LC7:
.string "recv failed"
.LC8:
.string "Reply received\n"
.text
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $2048, %rsp
movl %edi, -2036(%rbp)
movq %rsi, -2048(%rbp)
movl $0, %edx
movl $1, %esi
movl $2, %edi
call socket
movl %eax, -4(%rbp)
cmpl $-1, -4(%rbp)
jne .L2
movl $.LC0, %edi
movl $0, %eax
call printf
.L2:
movl $.LC1, %edi
call inet_addr
movl %eax, -28(%rbp)
movw $2, -32(%rbp)
movl $2000, %edi
call htons
movw %ax, -30(%rbp)
leaq -32(%rbp), %rcx
movl -4(%rbp), %eax
movl $16, %edx
movq %rcx, %rsi
movl %eax, %edi
call connect
testl %eax, %eax
jns .L3
movl $.LC2, %edi
call puts
movl $1, %eax
jmp .L7
.L3:
movl $.LC3, %edi
call puts
movq $.LC4, -16(%rbp)
movq -16(%rbp), %rax
movq %rax, %rdi
call strlen
movq %rax, %rdx
movq -16(%rbp), %rsi
movl -4(%rbp), %eax
movl $0, %ecx
movl %eax, %edi
call send
testq %rax, %rax
jns .L5
movl $.LC5, %edi
call puts
movl $1, %eax
jmp .L7
.L5:
movl $.LC6, %edi
call puts
leaq -2032(%rbp), %rsi
movl -4(%rbp), %eax
movl $0, %ecx
movl $2000, %edx
movl %eax, %edi
call recv
testq %rax, %rax
jns .L6
movl $.LC7, %edi
call puts
.L6:
movl $.LC8, %edi
call puts
leaq -2032(%rbp), %rax
movq %rax, %rdi
call puts
movl $0, %eax
.L7:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size main, .-main
.ident "GCC: (Debian 4.9.2-10) 4.9.2"
因此在使用example.s -o example.o后,我使用了ld example.o -o示例,这就是我得到以下错误的地方:
ld:警告:找不到条目符号_start;默认为00000000004000b0 test.o:在函数
main': test.c:(.text+0x28): undefined reference to
socket'中 test.c :(。text + 0x40):对printf' test.c:(.text+0x4a): undefined reference to
inet_addr'的未定义引用 test.c :(。text + 0x5d):对htons' test.c:(.text+0x77): undefined reference to
connect'的未定义引用 test.c :(。text + 0x85):对puts' test.c:(.text+0x99): undefined reference to
puts'的未定义引用 test.c :(。text + 0xad):对strlen' test.c:(.text+0xc3): undefined reference to
send'的未定义引用 test.c :(。text + 0xd2):对puts' test.c:(.text+0xe3): undefined reference to
puts'的未定义引用 test.c :(。text + 0xfe):对recv' test.c:(.text+0x10d): undefined reference to
puts'的未定义引用 test.c :(。text + 0x117):未定义引用puts' test.c:(.text+0x126): undefined reference to
puts'
在我看来,gcc没有正确使用.start,global main等等,但说实话我不知道如何解决它。如果这是正确的那么为什么呢?
任何帮助都会很感激。
谢谢。
答案 0 :(得分:2)
问题是ld example.o -o example
尝试仅链接example.o
而不是其他任何内容。要获得缺少的符号,您需要链接更多(例如,启动代码,标准库,C运行时等)。尝试gcc -v example.c
以查看应如何调用链接器。
答案 1 :(得分:2)
Harry's answer中给出的命令是好的:
gcc -Wall -O -fverbose-asm -S example.c
gcc -c example.s -o example.o
gcc example.o -o example
基本上,您应该知道GCC会将您的代码链接到:
libc.so
)(会做一些system calls)libgcc
提供一些低级,处理器特定的功能(例如32位机器上的64位算术);它有一个宽容但ad-hoc许可证。如何将所有这些链接在一起的是gcc
命令,它将启动一些ld
。在编译命令中将gcc
替换为gcc -v
,以了解究竟发生了什么。如果您想发布自己的ld
命令,则应添加提供上面列出的选项。你得到的错误主要是因为缺乏crt0
&amp; libc
另请尝试gcc -dumpspecs
,其中介绍what gcc
了解发出各种命令(注意gcc
只是一个驱动程序;真正的C编译器是{{1} }})。另请阅读GCC上的wikipage。 documentation of GCC MELT上的一些幻灯片和参考文献提供了更多信息。另见this及其中的图片。
我强烈建议您使用cc1
汇总(您的某些汇编代码)并链接内容(因为您不想要处理上面提到的所有血腥细节,加上我没有提到的其他一些细节。
答案 2 :(得分:1)
这是一个重要的部分:
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crt1.o
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/4.9/crtbegin.o
-lgcc
--as-needed -lgcc_s
--no-as-needed -lc -lgcc
--as-needed -lgcc_s
--no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.9/crtend.o
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crtn.o
crt1
,crti
,crtbegin
提供实际定义_start
入口点的启动代码(稍后控件将传递给您的main
),stdio
已初始化等。同样strand
和crtn
在main
返回后处理清理。 lc
提供标准库(如puts
和其他缺少的符号)。 lgcc
和lgcc_s
具有gcc
特定的运行时支持。
最重要的是,您需要将所有内容链接到其中。
答案 3 :(得分:0)
试试这个
gcc -Wall -O -fverbose-asm -S example.c
gcc -c example.s -o example.o
gcc example.o -o example