热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

32位linux安装64位工具链,在64位系统(GNU工具链)上组装32位二进制文件

使用gcc-m32..code32是吗?不更改输出文件格式,这就是程序运行模式的决定因素。不尝试在64位模式下运行32位代码是由您自己决定的。.code

使用gcc -m32.

.code32是吗?不更改输出文件格式,这就是程序运行模式的决定因素。不尝试在64位模式下运行32位代码是由您自己决定的。.code32用于组装您可能希望作为数据的“外部”机器代码,或用于在共享内存段中导出。如果这不是您所要做的,那么在构建一个.S如果它有任何错误的模式push或pop例如说明。

建议:使用.S手写体汇编程序的扩展。(gcc foo.S之前会在C预处理程序中运行它。as所以你可以#include例如,带有SysCall数字的头)。同时,它也区别于.s编译器输出(来自gcc foo.c -O3 -S).

要构建32位二进制文件,请使用以下命令之一

gcc -g foo.S -o foo -m32 -nostdlib -static  # static binary with absolutely no libraries or startup code

# -nostdlib by itself makes static executables on Linux, but not OS X.

gcc -g foo.S -o foo -m32                  # dynamic binary including the startup boilerplate code.  Use with code that defines a main() but not a _start

文件nostdlib, -nostartfiles,和-static.

使用libc函数_start(示例见这个答案的结尾)

一些功能,比如malloc(3),或stdio函数,包括printf(3),依赖于正在初始化的一些全局数据(例如,FILE *stdout以及它实际指向的对象)。

gcc -nostartfiles忽略CRT_start样板代码,但仍然链接libc(在默认情况下是动态的)。在linux上,共享库可以在动态链接器加载它们时由初始化器部分运行,然后跳到_start进入点。所以gcc -nostartfiles hello.S还让你打电话printf..对于动态可执行文件,内核运行/lib/ld-linux.so.2而不是直接运行它(使用readelf -a查看二进制文件中的“ELF解释器”字符串)。当你_start最终运行时,并不是所有的寄存器都会被归零,因为动态链接器在您的进程中运行代码。

然而,gcc -nostartfiles -static hello.S将链接,但在运行时崩溃。如果你打电话printf或者没有调用glibc内部init功能的东西。(见Michael Petch的评论)。

当然,你可以把任何组合.c, .S,和.o在同一个命令行中的文件,将所有文件链接到一个可执行文件中。如果你有C,别忘了-Og -Wall -Wextra:当C中的问题很简单时,您不想调试ASM,编译器可能已经警告过您了。

使用-v让GCC向您展示它运行的组装和链接命令。“手动”:

as foo.S -o foo.o -g --32 &&      # skips the preprocessor

ld -o foo foo.o  -m elf_i386

file foo

foo: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped

gcc -nostdlib -m32比AS和ld的两个不同选项更容易记住和键入(--32和-m elf_i386)。而且,它可以在所有平台上工作,包括那些可执行格式不是ELF的平台。(但是Linux示例不能在OSX上工作,因为系统调用号是不同的,或者在Windows上,因为它甚至不使用int 0x80(ABI.)

NASM/YASM

GCC不会处理NASM语法。(-masm=intel更像是MASM,而不是NASM语法,在这里您需要offset symbol以立即获得地址)。当然,指令是不同的。.globlVSglobal).

你可以用nasm或yasm,然后链接.o带着gcc如上所示,或ld直接。

我使用包装器脚本来避免重复输入具有三个不同扩展名的相同文件名。(NASM和Yasm默认为file.asm -> file.o,不像GNU的默认输出a.out)。用这个和-m32装配和连接32位ELF可执行文件。并不是所有的操作系统都使用ELF,所以这个脚本比使用gcc -nostdlib -m32链接就是.。

#!/bin/sh

# usage: asm-link [-q] [-m32] foo.asm  [assembler options ...]

# Just use a Makefile for anything non-trivial.  This script is intentionally minimal and doesn't handle multiple source files

verbose=1                       # defaults

fmt=-felf64

#ldopt=-melf_i386

while getopts 'm:vq' opt; do

case "$opt" in

m)  if [ "m$OPTARG" = "m32" ]; then

fmt=-felf32

ldopt=-melf_i386

fi

if [ "m$OPTARG" = "mx32" ]; then

fmt=-felfx32

ldopt=-melf32_x86_64

fi

# default is -m64

;;

q)  verbose=0 ;;

v)  verbose=1 ;;

esac

done

shift "$((OPTIND-1))"   # Shift off the options and optional --

src=$1

base=${src%.*}

shift

[ "$verbose" = 1 ] && set -x    # print commands as they're run, like make

#yasm "$fmt" -Worphan-labels -gdwarf2 "$src" "$@" &&

nasm "$fmt" -Worphan-labels -g -Fdwarf "$src" "$@" &&

ld $ldopt -o "$base" "$base.o"

# yasm -gdwarf2 includes even .local labels so they show up in objdump output

# nasm defaults to that behaviour of including even .local labels

# nasm defaults to STABS debugging format, but -g is not the default

我更喜欢亚玛斯,有几个原因,包括默认情况下不做太久-nops而不是填充许多单字节。nopS.这会导致混乱的反汇编输出,如果NOPS运行的话也会变慢。(在NASM中,您必须使用smartalign)宏包。)

示例:使用libc函数的程序

# hello32.S

#include    // syscall numbers.  only #defines, no C declarations left after CPP to cause asm syntax errors

.text

#.global main   # uncomment these to let this code work as _start, or as main called by glibc _start

#main:

#.weak _start

.global _start

_start:

mov     $__NR_gettimeofday, %eax  # make a syscall that we can see in strace output so we know when we get here

int     $0x80

push    %esp

push    $print_fmt

call   printf

#xor    %ebx,%ebx                 # _exit(0)

#mov    $__NR_exit_group, %eax    # same as glibc's _exit(2) wrapper

#int    $0x80                     # won't flush the stdio buffer

movl    $0, (%esp)   # reuse the stack slots we set up for printf, instead of popping

call    exit         # exit(3) does an fflush and other cleanup

#add    $8, %esp     # pop the space reserved by the two pushes

#ret                 # only works in main, not _start

.section .rodata

print_fmt: .asciz "Hello, World!\n%%esp at startup = %#lx\n"

$ gcc -m32 -nostdlib hello32.S

/tmp/ccHNGx24.o: In function `_start':

(.text+0x7): undefined reference to `printf'

...

$ gcc -m32 hello32.S

/tmp/ccQ4SOR8.o: In function `_start':

(.text+0x0): multiple definition of `_start'

...

在运行时失败,因为没有调用glibc init函数。(__libc_init_first, __dl_tls_setup,和__libc_csu_init根据迈克尔·佩奇的评论。其他libc存在实现,包括MUSL它是为静态链接而设计的,无需初始化调用即可工作。)

$ gcc -m32 -nostartfiles -static hello32.S     # fails at run-time

$ file a.out

a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, BuildID[sha1]=ef4b74b1c29618d89ad60dbc6f9517d7cdec3236, not stripped

$ strace -s128 ./a.out

execve("./a.out", ["./a.out"], [/* 70 vars */]) = 0

[ Process PID=29681 runs in 32 bit mode. ]

gettimeofday(NULL, NULL)                = 0

--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---

+++ killed by SIGSEGV (core dumped) +++

Segmentation fault (core dumped)

你也可以gdb ./a.out,然后跑b _start, layout reg, run看看会发生什么。

$ gcc -m32 -nostartfiles hello32.S             # Correct command line

$ file a.out

a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=7b0a731f9b24a77bee41c13ec562ba2a459d91c7, not stripped

$ ./a.out

Hello, World!

%esp at startup = 0xffdf7460

$ ltrace -s128 ./a.out > /dev/null

printf("Hello, World!\n%%esp at startup = %#lx\n", 0xff937510)      = 43    # note the different address: Address-space layout randomization at work

exit(0

+++ exited (status 0) +++

$ strace -s128 ./a.out > /dev/null        # redirect stdout so we don't see a mix of normal output and trace output

execve("./a.out", ["./a.out"], [/* 70 vars */]) = 0

[ Process PID=29729 runs in 32 bit mode. ]

brk(0)                                  = 0x834e000

access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)

....   more syscalls from dynamic linker code

open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3

mmap2(NULL, 1814236, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xfffffffff7556000    # map the executable text section of the library

... more stuff

# end of dynamic linker's code, finally jumps to our _start

gettimeofday({1461874556, 431117}, NULL) = 0

fstat64(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0  # stdio is figuring out whether stdout is a terminal or not

ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0xff938870) = -1 ENOTTY (Inappropriate ioctl for device)

mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff7743000      # 4k buffer for stdout

write(1, "Hello, World!\n%esp at startup = 0xff938fb0\n", 43) = 43

exit_group(0)                           = ?

+++ exited with 0 +++

如果我们用_exit(0),或使sys_exit系统自称为int 0x80, 这个write(2)不会发生..当stdout重定向到非TTY时,它默认为全缓冲(不是行缓冲),因此write(2)仅由fflush(3)作为exit(3)..没有重定向,呼叫printf(3)包含换行符的字符串将立即刷新。

不同的行为取决于stdout是否是终端可能是可取的,但前提是您是故意的,而不是错误的。



推荐阅读
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • 加密世界下一个主流叙事领域:L2、跨链桥、GameFi等
    本文介绍了加密世界下一个主流叙事的七个潜力领域,包括L2、跨链桥、GameFi等。L2作为以太坊的二层解决方案,在过去一年取得了巨大成功,跨链桥和互操作性是多链Web3中最重要的因素。去中心化的数据存储领域也具有巨大潜力,未来云存储市场有望达到1500亿美元。DAO和社交代币将成为购买和控制现实世界资产的重要方式,而GameFi作为数字资产在高收入游戏中的应用有望推动数字资产走向主流。衍生品市场也在不断发展壮大。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
author-avatar
乌桥老鹅
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有